আধুনিক সি ++ কী বিনামূল্যে আপনাকে পারফরম্যান্স পেতে পারে?


205

কখনও কখনও দাবি করা হয় যে সি ++ 11/14 আপনাকে কেবল সি ++ 98 কোডটি সংকলন করার পরেও একটি পারফরম্যান্স উত্সাহ পেতে পারে। ন্যায়সঙ্গততা সাধারণত সরানো শব্দার্থবিরোধী লাইনের সাথে থাকে, কারণ কিছু ক্ষেত্রে রাল্যু কনস্ট্রাক্টরগুলি স্বয়ংক্রিয়ভাবে উত্পন্ন হয় বা এখন এসটিএলের অংশ। এখন আমি ভাবছি যে এই মামলাগুলি আসলে ইতিমধ্যে আরভিও বা অনুরূপ সংকলক অপ্টিমাইজেশান দ্বারা পরিচালিত হয়েছিল কিনা।

আমার প্রশ্নটি হ'ল আপনি যদি আমাকে সি ++ 98 কোডের একটি টুকরোটির প্রকৃত উদাহরণ দিতে পারেন যা কোনও পরিবর্তন ছাড়াই নতুন ভাষার বৈশিষ্ট্যগুলিকে সমর্থন করে একটি সংকলক ব্যবহার করে দ্রুত চলে runs আমি বুঝতে পারি যে একটি স্ট্যান্ডার্ড কনফর্মিং সংকলক অনুলিপিটিকরণের প্রয়োজন নেই এবং কেবল সে কারণেই পদার্থবিজ্ঞানগুলি গতি আনতে পারে তবে আপনি যদি চান তবে আমি একটি কম প্যাথলজিকাল কেস দেখতে চাই।

সম্পাদনা: পরিষ্কার করার জন্য, আমি জিজ্ঞাসা করছি না যে নতুন সংকলকগুলি পুরানো সংকলকগুলির তুলনায় দ্রুততর কিনা তা নয়, বরং যদি আমার সংকলক পতাকাগুলিতে -std = c ++ 14 যুক্ত করে কোড থাকে তবে এটি দ্রুত চলবে (অনুলিপিগুলি এড়ান, তবে আপনি যদি পদার্থবিজ্ঞানের চলা ছাড়াও অন্য যে কোনও কিছু নিয়ে আসতে পারে, আমিও আগ্রহী হব)


3
মনে রাখবেন একটি অনুলিপি কনস্ট্রাক্টর ব্যবহার করে কোনও নতুন অবজেক্ট তৈরি করার সময় কপির এলিজেন এবং রিটার্ন মান অপ্টিমাইজেশন করা হয়। তবে, একটি অনুলিপি অ্যাসাইনমেন্ট অপারেটরে, কোনও অনুলিপি এলিজেন নেই (এটি কীভাবে হতে পারে, যেহেতু সংকলক অস্থায়ী নয় এমন ইতিমধ্যে নির্মিত বস্তুর সাথে কী করণীয় তা জানে না)। সুতরাং, সেক্ষেত্রে, সি ++ 11/14 বড় পদক্ষেপ গ্রহণ করে, আপনাকে একটি সরানো অ্যাসাইনমেন্ট অপারেটর ব্যবহারের সম্ভাবনা দিয়ে। যদিও আপনার প্রশ্ন সম্পর্কে, আমি মনে করি না যে সি ++ 98 কোডটি সি ++ 11/14 সংকলক দ্বারা সংকলিত হলে দ্রুত হওয়া উচিত, সম্ভবত এটি আরও দ্রুততর কারণ সংকলকটি আরও নতুন।
ভিসফটকো

27
এছাড়াও স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে এমন কোডগুলি সম্ভবত সি ++ 98 এর সাথে পুরোপুরি সামঞ্জস্যপূর্ণ করা সত্ত্বেও, কারণ সি ++ 11/14-এ অন্তর্নিহিত পাঠাগারটি সম্ভব হলে অভ্যন্তরীণভাবে শব্দার্থক পদক্ষেপ ব্যবহার করে। সুতরাং যে কোডটি সি ++ 98 এবং সি ++ 11/14-তে অভিন্ন দেখায় তা পরবর্তী ক্ষেত্রে (সম্ভবত) দ্রুততর হবে, যখনই আপনি ভেক্টর, তালিকা ইত্যাদির মতো স্ট্যান্ডার্ড লাইব্রেরি অবজেক্টগুলি ব্যবহার করেন এবং শব্দার্থবিজ্ঞানের স্থান পরিবর্তন করে।
বনামসফ্টকো

1
@ ভসফটকো, আমি সেই ধরণের পরিস্থিতিটিই ইঙ্গিত করছিলাম, তবে একটি উদাহরণ সামনে আসতে পারলাম না: আমার মনে আছে যা থেকে যদি আমাকে অনুলিপি নির্ধারণকারীকে সংজ্ঞায়িত করতে হয় তবে মুভ কনস্ট্রাক্টর স্বয়ংক্রিয়ভাবে উত্পন্ন হবে না, যা আমাদের ছেড়ে চলে যায় খুব সহজ ক্লাস যেখানে আরভিও, আমার মনে হয়, সর্বদা কাজ করে। একটি ব্যতিক্রম এসটিএল কনটেইনারগুলির সাথে জড়িত কিছু হতে পারে, যেখানে পাঠাগার প্রয়োগকারী দ্বারা রাল্যু কনস্ট্রাক্টর তৈরি করা হয় (যার অর্থ চলন্তগুলি ব্যবহারের জন্য কোডটিতে আমাকে কোনও পরিবর্তন করতে হবে না)।
শে

একটি অনুলিপি নির্মাণকারী না থাকার জন্য ক্লাসগুলি সহজ হতে হবে না। সি ++ ভ্যালু সিম্যান্টিক্সে সাফল্য অর্জন করে এবং অনুলিপি নির্মাণকারী, অ্যাসাইনমেন্ট অপারেটর, ডেস্ট্রাক্টর ইত্যাদি ব্যতিক্রম হওয়া উচিত।
sp2danny

1
@ এরিক লিঙ্কটির জন্য আপনাকে ধন্যবাদ, এটি আকর্ষণীয় ছিল। তবে, দ্রুত এটিকে সন্ধান করার পরে, এর গতির সুবিধাগুলি বেশিরভাগই std::moveকন্সট্রাক্টরদের যোগ এবং সরানো থেকে আসে (যা বিদ্যমান কোডে পরিবর্তনের প্রয়োজন হবে)। আমার প্রশ্নের সাথে সত্যিই সম্পর্কিত কেবলমাত্র বাক্যটি ছিল "আপনি কেবল পুনরায় সংশোধন করে তাত্ক্ষণিক গতির সুবিধাগুলি পান", যা কোনও উদাহরণ দ্বারা ব্যাক আপ হয় না (এটি একই প্রশ্নে এসটিএল উল্লেখ করে, যেমনটি আমি আমার প্রশ্নে করেছি, তবে নির্দিষ্ট কিছুই নয়) )। আমি কিছু উদাহরণ চাইছিলাম। আমি যদি স্লাইডগুলি ভুলভাবে পড়ছি তবে আমাকে জানান।
23:25

উত্তর:


221

আমি ৫ টি সাধারণ বিভাগ সম্পর্কে সচেতন যেখানে সি ++ ১১ হিসাবে একটি সি ++ ০৩ সংকলক পুনরায় সংযোগ করা আনবাউন্ড পারফরম্যান্স বৃদ্ধির কারণ হতে পারে যা কার্যত বাস্তবায়নের মানের সাথে সম্পর্কিত নয়। এগুলি চলন্ত শব্দার্থবিজ্ঞানের সমস্ত প্রকরণ।

std::vector বরাদ্দ

struct bar{
  std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03

প্রত্যেক সময় fooএর বাফার C ++ 03 পুনরায় বরাদ্দ করা হয় তা প্রত্যেক কপি vectorমধ্যে bar

সি ++ 11 এ এটি পরিবর্তিতভাবে এসগুলি সরিয়ে দেয় bar::dataযা মূলত বিনামূল্যে।

এই ক্ষেত্রে, এই ভিতরে অপ্টিমাইজেশন উপর নির্ভর stdধারক vector। নীচের প্রতিটি ক্ষেত্রে, stdপাত্রে ব্যবহার কেবলমাত্র কারণ moveআপনি যখন আপনার সংকলক আপগ্রেড করেন তখন সি ++ 11 "স্বয়ংক্রিয়ভাবে" তে দক্ষ শব্দার্থক থাকে সেগুলি সি ++ অবজেক্ট । যে সামগ্রীগুলি এটি একটি stdপাত্রে অন্তর্ভুক্ত করে তা অবরুদ্ধ করে না সেগুলি স্বয়ংক্রিয়ভাবে উন্নত moveকনস্ট্রাক্টরের উত্তরাধিকারী ।

এনআরভিও ব্যর্থতা

যখন এনআরভিও (নামযুক্ত রিটার্ন মান অপ্টিমাইজেশন) ব্যর্থ হয়, সি ++ 03 এ এটি অনুলিপি পিছনে পড়ে যায়, সি ++ 11 এ এটি চলাচলে ফিরে যায়। এনআরভিওর ব্যর্থতা সহজ:

std::vector<int> foo(int count){
  std::vector<int> v; // oops
  if (count<=0) return std::vector<int>();
  v.reserve(count);
  for(int i=0;i<count;++i)
    v.push_back(i);
  return v;
}

অথবা এমনকি:

std::vector<int> foo(bool which) {
  std::vector<int> a, b;
  // do work, filling a and b, using the other for calculations
  if (which)
    return a;
  else
    return b;
}

আমাদের তিনটি মান রয়েছে - ফাংশনের মধ্যে ফেরতের মান এবং দুটি পৃথক মান। এলিশন ফাংশনটির মধ্যে থাকা মানগুলিকে রিটার্ন মানটির সাথে 'একত্রিত' করতে দেয় তবে একে অপরের সাথে নয়। একে অপরের সাথে একত্রিত না হয়ে তারা উভয়ই রিটার্ন মানের সাথে একত্রী হতে পারে না।

মূল সমস্যাটি হ'ল এনআরভিও এলিজেনটি ভঙ্গুর এবং returnসাইটের কাছাকাছি না হওয়া পরিবর্তনের কোডটি হঠাৎ করে কোনও ডায়াগনস্টিক নির্গমন ছাড়াই সেই জায়গাটিতে ব্যাপক পারফরম্যান্স হ্রাস পেতে পারে। বেশিরভাগ এনআরভিও ব্যর্থতার ক্ষেত্রে সি ++ 11 এর সাথে শেষ হয় move, আর সি ++ 03 একটি অনুলিপি সহ শেষ হয়।

একটি ফাংশন যুক্তি ফিরে

এলিজেন এখানেও অসম্ভব:

std::set<int> func(std::set<int> in){
  return in;
}

সি ++ 11 এ এটি সস্তা: সি ++ 03 এ অনুলিপিটি এড়ানোর কোনও উপায় নেই। ফাংশনগুলিতে যুক্তিগুলি রিটার্ন মানের সাথে আলাদা করা যায় না, কারণ প্যারামিটারের জীবনকাল এবং অবস্থান এবং রিটার্ন মান কলিং কোড দ্বারা পরিচালিত হয়।

তবে সি ++ 11 এক থেকে অন্যটিতে যেতে পারে। (একটি খেলনা উদাহরণে, কিছু কিছু করা হতে পারে set)।

push_back অথবা insert

অবশেষে ধারকগুলিতে এলিজেনটি ঘটে না: তবে সি ++ 11 ওভারলোডগুলি চালকগুলি সন্নিবেশ করান, যা অনুলিপিগুলি সংরক্ষণ করে।

struct whatever {
  std::string data;
  int count;
  whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );

সি ++ 03 এ একটি অস্থায়ী whateverতৈরি হয়, তারপরে এটি ভেক্টরে অনুলিপি করা হয় v। 2 টি std::stringবাফার বরাদ্দ করা হয়েছে, প্রতিটি অভিন্ন ডেটা সহ এবং একটি ত্যাগ করা হয়।

সি ++ 11 এ একটি অস্থায়ী whateverতৈরি করা হয়। এর পরে whatever&& push_backওভারলোড moveভেক্টরটিতে সেই অস্থায়ী v। একটি std::stringবাফার বরাদ্দ করা হয়েছে, এবং ভেক্টরে সরানো হয়েছে। একটি খালি std::stringফেলে দেওয়া হয়।

নিয়োগ

নীচে @ জারোড 42 এর উত্তর থেকে চুরি হয়েছে।

এলিজেনশন অ্যাসাইনমেন্টের সাথে ঘটতে পারে না, তবে স্থানান্তর থেকে পারে।

std::set<int> some_function();

std::set<int> some_value;

// code

some_value = some_function();

এখানে some_functionথেকে একজন প্রার্থীকে এলিডে ফিরিয়ে দেয়, তবে এটি সরাসরি কোনও অবজেক্ট তৈরি করতে ব্যবহৃত না হওয়ায় এটি আলাদা করা যায় না। সি ++ তে, উপরের ফলাফলগুলিতে অস্থায়ী সামগ্রীতে অনুলিপি করা হচ্ছে some_value। সি ++ 11 এ এটি সরানো হয়েছে some_value, যা মূলত বিনামূল্যে।


উপরের পুরো প্রভাবের জন্য, আপনার কাছে এমন একটি সংকলক প্রয়োজন যা মুভ কনস্ট্রাক্টর এবং অ্যাসাইনমেন্টকে সংশ্লেষিত করে।

এমএসভিসি 2013 এর মধ্যে মুভ কনস্ট্রাক্টরগুলি প্রয়োগ করে std কনটেইনারগুলিতে করে, তবে আপনার ধরণের মুভ কনস্ট্রাক্টরগুলিকে সংশ্লেষিত করে না।

সুতরাং std::vectorএস এবং অনুরূপ সমন্বিত ধরণেরগুলি এমএসভিসি ২০১৩ তে এই ধরনের উন্নতি পায় না, তবে তাদের এমএসভিসি ২০১৫ এ পাওয়া শুরু করবে।

ঝনঝন এবং জিসিসি দীর্ঘকাল থেকেই অন্তর্নিহিত মুভ কনস্ট্রাক্টর প্রয়োগ করেছে। ইন্টেলের 2013 সংকলক আপনি পাস করলে -Qoption,cpp,--gen_move_operationsমুভি কনস্ট্রাক্টরের অন্তর্নিহিত প্রজন্মকে সমর্থন করবে (তারা এমএসভিসি ২০১৩ এর সাথে ক্রস-সামঞ্জস্যপূর্ণ হওয়ার প্রয়াসে ডিফল্টরূপে এটি করবেন না)।


1
@ বড় করুন হ্যাঁ তবে কোনও মুভ কনস্ট্রাক্টর কপি কনস্ট্রাক্টরের চেয়ে বহুগুণ বেশি দক্ষ হওয়ার জন্য সাধারণত এগুলি অনুলিপি করার পরিবর্তে সংস্থানগুলি সরিয়ে নিতে হয়। আপনার নিজের মুভ কনস্ট্রাক্টর (এবং কেবল একটি সি ++ 03 প্রোগ্রাম পুনরায় সংকলন) না লিখে stdগ্রন্থাগারের পাত্রে সমস্তগুলি move"বিনা মূল্যে" কনস্ট্রাক্টরের সাথে আপডেট করা হবে এবং (যদি আপনি এটি অবরুদ্ধ না করেন) কনস্ট্রাক্টস যা অবজেক্ট অবজেক্ট ব্যবহার করে ( এবং বলেছে যে অবজেক্টগুলি) বেশ কয়েকটি পরিস্থিতিতে নিখরচায় নির্মাণের কাজ শুরু করবে। এই পরিস্থিতিতে অনেকগুলি সি ++ 03 এ এলিজেন দ্বারা আচ্ছাদিত: সমস্ত নয়।
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট

5
এটি তখন একটি খারাপ অপ্টিমাইজার বাস্তবায়ন, কারণ ভিন্ন ভিন্ন নামযুক্ত জিনিসগুলি ফিরিয়ে দেওয়া হচ্ছে আজীবন ওভারল্যাপিং নেই, আরভিও তাত্ত্বিকভাবে এখনও সম্ভব।
বেন ভয়েগ্ট

2
@ এলার্জ এমন জায়গাগুলি রয়েছে যেখানে এলিজেন ব্যর্থ হয়, যেমন যখন ওভারল্যাপিং লাইফটাইমযুক্ত দুটি বস্তুকে তৃতীয় অংশে আলাদা করা যায় তবে একে অপরকে নয়। তারপরে সি ++ 11 এ সরানো প্রয়োজন, এবং সি ++ 03 এ অনুলিপি করুন (যেমন-উপেক্ষা করে)। এলিশন অনুশীলনে প্রায়শই ভঙ্গুর হয়। stdউপরের কন্টেইনারগুলির ব্যবহার বেশিরভাগ কারণ সি ++ ১১ এর পুনঃসংযোগ করার সময় আপনি সি ++ 11 তে 'ফ্রি' পাবেন এমন কপি করার জন্য বহুল পরিমাণে সরানো সস্তা। vector::resizeএকটি ব্যতিক্রম হল: এটি ব্যবহার করে moveC ++ 11।
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট

27
আমি কেবলমাত্র 1 সাধারণ বিভাগ দেখতে পাচ্ছি যা পদার্থ চলাচল, এবং এর 5 টি বিশেষ ক্ষেত্রে।
জোহানেস স্কাউব -

3
@ সেব্রো আমি বুঝতে পেরেছি, আপনি "প্রোগ্রামগুলি বহু কিলোবাইটের অনেকগুলি বরাদ্দ না করার কারণ হিসাবে বিবেচনা করেন না এবং পরিবর্তে পয়েন্টারগুলিকে প্রায় স্থানান্তরিত করেন" পর্যাপ্ত হতে পারে। আপনি সময়সীমার ফলাফল চান। আপনি যে মৌলিকভাবে কম করছেন তার প্রমাণের চেয়ে মাইক্রোবেঞ্চমার্কগুলি পারফরম্যান্স উন্নতির আর কোনও প্রমাণ নয়। বাস্তব বিশ্বের কাজগুলির প্রোফাইলিংয়ের সাথে বিস্তৃত বিভিন্ন শিল্পের কয়েকটি 100 টি বাস্তব বিশ্বের অ্যাপ্লিকেশনগুলির সংক্ষিপ্ততা প্রমাণ নয়। আমি "ফ্রি পারফরম্যান্স" সম্পর্কে অস্পষ্ট দাবি নিয়েছি এবং তাদের C ++ 03 এবং C ++ 11 এর অধীনে প্রোগ্রামের আচরণের পার্থক্য সম্পর্কে সুনির্দিষ্ট তথ্য তৈরি করেছি।
ইয়াক্ক - অ্যাডাম নেভ্রামাউন্ট

46

যদি আপনার মতো কিছু থাকে:

std::vector<int> foo(); // function declaration.
std::vector<int> v;

// some code

v = foo();

আপনি সি ++ 03 এ একটি অনুলিপি পেয়েছেন, অন্যদিকে আপনি C ++ 11 এ একটি সরানো নিয়োগ পেয়েছেন। সুতরাং আপনার ক্ষেত্রে সেই ক্ষেত্রে নিখরচায় অপ্টিমাইজেশন রয়েছে।


4
@ ইয়াক্ক: অ্যাসাইনমেন্টে অনুলিপিটি কীভাবে ঘটে?
জারোড 42

2
@ জারোড I২২ আমি আরও বিশ্বাস করি যে কোনও কার্যালয়ে অনুলিপি তৈরি করা সম্ভব নয়, বাম দিকটি ইতিমধ্যে নির্মিত হয়েছে এবং ডান থেকে সংস্থানগুলি চুরি করার পরে "পুরাতন" ডেটা দিয়ে কী করা উচিত তা জানতে কোনও কম্পাইলারের পক্ষে যুক্তিসঙ্গত উপায় নেই হাত পাশ তবে সম্ভবত আমি ভুল, আমি উত্তরটি চিরকালের জন্য খুঁজে পেতে পছন্দ করব। অনুলিপিটি তৈরি করার সময় আপনি অনুলিপিটি তৈরি করতে পারেন, কারণ বস্তুটি "তাজা" এবং পুরানো ডেটা দিয়ে কী করবেন তা সিদ্ধান্ত নিতে কোনও সমস্যা নেই। যতদূর আমি জানি, একমাত্র ব্যতিক্রম এটি: "দায়িত্ব কেবলমাত্র বিধি অনুসারে
আলাদা করা

4
foo().swap(v);
বেন ভয়েগট

@ বেনভয়েগ নিশ্চিত, তবে সমস্ত কোড অপ্টিমাইজড হয় না এবং যেখানে ঘটে যায় এমন সমস্ত দাগ সহজেই পৌঁছায় না।
ইয়াক - অ্যাডাম নেভ্রামুমন্ট

@ বেনভয়েট বলেছেন যে অনুলিপি বর্ধন একটি অ্যাসাইনমেন্টে কাজ করতে পারে। আরও ভাল শব্দটি হল আরভিও (রিটার্ন মান অপ্টিমাইজেশন) এবং কেবল তখনই কাজ করে যদি foo () এর মতো প্রয়োগ করা হয়।
ড্রাম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.