ভার্চুয়াল ফাংশন এবং কর্মক্ষমতা - সি ++


125

আমার ক্লাস ডিজাইনে আমি বিমূর্ত ক্লাস এবং ভার্চুয়াল ফাংশনগুলি ব্যাপকভাবে ব্যবহার করি। আমার অনুভূতি ছিল যে ভার্চুয়াল ফাংশনগুলি কার্য সম্পাদনকে প্রভাবিত করে। এটা কি সত্য? তবে আমি মনে করি এই পারফরম্যান্স পার্থক্যটি লক্ষণীয় নয় এবং দেখে মনে হচ্ছে অকাল অপ্টিমাইজেশন করছি। রাইট?


আমার উত্তর অনুসারে, আমি এটিকে স্টকওভারফ্লো ডব্লিকেট
সুমা


2
আপনি যদি উচ্চ পারফরম্যান্স কম্পিউটিং এবং নম্বর ক্রাঞ্চিং করছেন, গণনার মূল অংশে কোনও কার্যকারিতা ব্যবহার করবেন না: এটি অবশ্যই সমস্ত পারফরম্যান্সকে মেরে ফেলেছে এবং সংকলন-সময়ে অপ্টিমাইজেশানগুলি রোধ করে। প্রোগ্রামটির সূচনা বা চূড়ান্তকরণের জন্য এটি গুরুত্বপূর্ণ নয়। ইন্টারফেসের সাথে কাজ করার সময়, আপনি নিজের ইচ্ছামত ভার্চুয়ালটি ব্যবহার করতে পারেন।
ভিনসেন্ট

উত্তর:


90

থাম্বের একটি ভাল নিয়ম হ'ল:

যতক্ষণ না আপনি এটি প্রমাণ করতে পারেন এটি কোনও পারফরম্যান্স সমস্যা নয়।

ভার্চুয়াল ফাংশনগুলির ব্যবহারের পারফরম্যান্সের উপর খুব সামান্য প্রভাব পড়বে, তবে এটি আপনার অ্যাপ্লিকেশনটির সামগ্রিক কর্মক্ষমতা প্রভাবিত করার সম্ভাবনা কম। কর্মক্ষমতা উন্নতির সন্ধানের জন্য আরও ভাল জায়গা হ'ল অ্যালগরিদম এবং I / O।

ভার্চুয়াল ফাংশন (এবং আরও) সম্পর্কে কথা বলার একটি দুর্দান্ত নিবন্ধটি সদস্য ফাংশন পয়েন্টার ও দ্রুততম সম্ভাব্য সি ++ প্রতিনিধিদের


খাঁটি ভার্চুয়াল ফাংশন সম্পর্কে কি? তারা কোনওভাবেই পারফরম্যান্সকে প্রভাবিত করে? কেবল অবাক হওয়ার মতো দেখে মনে হচ্ছে যে তারা বাস্তবায়ন কার্যকর করার জন্য কেবল সেখানে রয়েছে।
থমথম

2
@ থমথম: সঠিক, খাঁটি ভার্চুয়াল এবং সাধারণ ভার্চুয়াল ফাংশনগুলির মধ্যে পারফরম্যান্সের পার্থক্য নেই।
গ্রেগ হিউগিল

168

আপনার প্রশ্নটি আমাকে কৌতূহলযুক্ত করেছিল, তাই আমি এগিয়ে গিয়ে 3 জিএইচজেড-এর অর্ডার পাওয়ার পাওয়ার সিপিসি সিপিইউতে কিছু সময় চালিয়েছিলাম with আমি যে পরীক্ষাটি চালিয়েছি তা হ'ল / সেট ফাংশনগুলি সহ একটি সাধারণ 4 ডি ভেক্টর ক্লাস করা

class TestVec 
{
    float x,y,z,w; 
public:
    float GetX() { return x; }
    float SetX(float to) { return x=to; }  // and so on for the other three 
}

তারপরে আমি এই ভেক্টরগুলির মধ্যে 1024 টি সমন্বিত তিনটি অ্যারে সেট করেছিলাম (এল 1-এ ফিট করার পক্ষে যথেষ্ট ছোট) এবং একটি লুপ চালিয়েছিলাম যা তাদের একে অপরের সাথে যুক্ত করেছে (Ax = Bx + Cx) 1000 বার। আমি ফাংশন হিসাবে সংজ্ঞায়িত সঙ্গে এই দৌড়ে inline, virtualএবং নিয়মিত ফাংশন কল। ফলাফল এখানে:

  • ইনলাইন: 8 এমএস (কল প্রতি 0.65ns)
  • সরাসরি: 68ms (প্রতি কল 5.53ns)
  • ভার্চুয়াল: 160ms (প্রতি কল 13ns)

সুতরাং, এই ক্ষেত্রে (যেখানে সবকিছু ক্যাশে ফিট করে) ভার্চুয়াল ফাংশন কলগুলি ইনলাইন কলগুলির চেয়ে প্রায় 20x কম ছিল। কিন্তু এই সত্যিই কি মানে? লুপের মাধ্যমে প্রতিটি ট্রিপ হুবহু 3 * 4 * 1024 = 12,288ফাংশন কলগুলির কারণ ঘটায় (1024 ভেক্টর চারবার চার বারের বার তিন যোগে তিন কল), তাই এই সময়গুলি 1000 * 12,288 = 12,288,000ফাংশন কলগুলি উপস্থাপন করে। ভার্চুয়াল লুপটি সরাসরি লুপের চেয়ে 92 মিমি বেশি সময় নিয়েছিল, সুতরাং কলটিতে অতিরিক্ত ওভারহেডটি 7 ন্যানোসেকেন্ড ছিল ফাংশন অনুযায়ী ।

এ থেকে আমি উপসংহারে পৌঁছেছি: হ্যাঁ , ভার্চুয়াল ফাংশনগুলি সরাসরি ফাংশনগুলির থেকে অনেক ধীর এবং না , যদি না তুমি পরিকল্পনা তাদের প্রতি সেকেন্ডে দশ লক্ষ গুণ কলিং, এটি কোন ব্যাপার না।

আরও দেখুন: উত্পন্ন সমাবেশের তুলনা।


তবে যদি তাদের একাধিকবার বলা হয়, তবে তারা কেবলমাত্র একবারে ডাকা হয়ে যাওয়ার চেয়ে সস্তা। আমার অপ্রাসঙ্গিক ব্লগ দেখুন: phresnel.org/blog , "ভার্চুয়াল ফাংশনগুলি ক্ষতিকারক নয় বলে বিবেচিত" শিরোনাম পোস্টগুলি, তবে অবশ্যই এটি আপনার কোডপথগুলির জটিলতার উপর নির্ভর করে
সেবাস্তিয়ান

22
আমার পরীক্ষাটি ভার্চুয়াল ফাংশনগুলির একটি ছোট সেটকে বারবার বলা হয়। আপনার ব্লগ পোস্টটি ধরে নিয়েছে যে কোডের সময় ব্যয় অপারেশন গণনা দ্বারা পরিমাপ করা যেতে পারে, তবে এটি সর্বদা সত্য নয়; আধুনিক প্রসেসরগুলির উপর একটি ভিফঙ্কের প্রধান ব্যয় হ'ল একটি শাখার ভুল অনুমানের কারণে পাইপলাইন বুদবুদ।
ক্র্যাশ ওয়ার্কস

10
এটি জিসিসি এলটিওর (লিঙ্ক টাইম অপটিমাইজেশন) জন্য একটি দুর্দান্ত মানদণ্ড হবে; এটিকে আবার lto সক্ষম সহ সংকলন করার চেষ্টা করুন: gcc.gnu.org/wiki/LinkTimeOptimization এবং দেখুন 20x ফ্যাক্টরের সাথে কী ঘটে
লুরসার

1
যদি কোনও শ্রেণীর একটি ভার্চুয়াল এবং একটি ইনলাইন ফাংশন থাকে তবে নন-ভার্চুয়াল পদ্ধতির কার্যকারিতাও প্রভাবিত হবে? প্রকৃতপক্ষে ক্লাস ভার্চুয়াল হচ্ছে?
থমথম

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

42

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


4
আমি নিশ্চিত নই যে আইফোন পারফরম্যান্ট কোডের একটি ভাল উদাহরণ: youtube.com/watch?v=Pdk2cJpSXLg
ক্র্যাশ ওয়ার্কস

13
@ ক্র্যাশওয়ার্কস: আইফোন মোটেই কোডের উদাহরণ নয়। এটি হার্ডওয়ারের একটি উদাহরণ - বিশেষত ধীরে ধীরে হার্ডওয়্যার , যা আমি এখানে তৈরি করছিলাম। এই স্বীকৃত "ধীর" ভাষা যদি আন্ডারপাওয়ার্ড হার্ডওয়ারের পক্ষে যথেষ্ট ভাল হয় তবে ভার্চুয়াল ফাংশনগুলি একটি বিশাল সমস্যা হতে পারে না।
চক

52
আইফোনটি একটি এআরএম প্রসেসরের উপর চলে। আইওএসের জন্য ব্যবহৃত এআরএম প্রসেসরগুলি কম মেগাহার্টজ এবং কম শক্তি ব্যবহারের জন্য ডিজাইন করা হয়েছে। সিপিইউতে শাখার পূর্বাভাসের জন্য কোনও সিলিকন নেই এবং তাই ভার্চুয়াল ফাংশন কলগুলি থেকে শাখার পূর্বাভাস থেকে কোনও পারফরম্যান্স ওভারহেড মিস হয় না। এছাড়াও আইওএস হার্ডওয়ারের জন্য মেগাহার্টজ পর্যাপ্ত পরিমাণে কম যে কোনও র‌্যাশ থেকে ডেটা পুনরুদ্ধার করার সময় ক্যাশে মিস 300 ঘড়ির চক্রের জন্য প্রসেসর স্টল করে না। লো মেগাহার্টজ এ ক্যাশে মিস করা কম গুরুত্বপূর্ণ। সংক্ষেপে, আইওএস ডিভাইসে ভার্চুয়াল ফাংশন ব্যবহার করা থেকে কোনও ওভারহেড নেই, তবে এটি একটি হার্ডওয়্যার সমস্যা এবং ডেস্কটপস সিপিইউগুলিতে প্রয়োগ হয় না।
হ্যালটিংস্টেট

4
দীর্ঘ সময় জাভা প্রোগ্রামার নতুনভাবে সি ++ এ যুক্ত হওয়ায় আমি যুক্ত করতে চাই যে জাভার জেআইটি সংকলক এবং রান-টাইম অপ্টিমাইজারের পূর্ব নির্ধারিত সংখ্যক লুপের পরে রান-টাইমে কিছু ফাংশন সংকলন, ভবিষ্যদ্বাণী করা এবং এমনকি ইনলাইন করার ক্ষমতা রয়েছে। তবে আমি নিশ্চিত নই যে সি ++ এর সংকলন এবং লিঙ্ক টাইমে এমন বৈশিষ্ট্য রয়েছে কারণ এতে রানটাইম কল প্যাটার্নের অভাব রয়েছে। সুতরাং সি ++ এ আমাদের সামান্য সতর্ক হওয়া দরকার।
অ্যালেক্স সু

@ অ্যালেক্সসো আমি আপনার বক্তব্য সম্পর্কে নিশ্চিত নই? সংকলিত হচ্ছে, সি ++ অবশ্যই রানটাইমের সময় কী ঘটতে পারে তার উপর ভিত্তি করে অনুকূলিত করতে পারে না, সুতরাং সিপিইউ নিজেই পূর্বাভাস ইত্যাদি করতে হবে ... তবে ভাল সি ++ সংকলক (যদি নির্দেশিত হয়) ফাংশনগুলি এবং লুপগুলি অনেক আগে অপ্টিমাইজ করার জন্য দুর্দান্ত দৈর্ঘ্যে যায় রানটাইম।
আন্ডারস্কোর_ড

34

খুব কার্য সম্পাদনের সমালোচনামূলক অ্যাপ্লিকেশনগুলিতে (ভিডিও গেমগুলির মতো) ভার্চুয়াল ফাংশন কলটি খুব ধীর হতে পারে। আধুনিক হার্ডওয়্যার সহ, সবচেয়ে বড় পারফরম্যান্স উদ্বেগ হ'ল ক্যাশে মিস। যদি ডেটা ক্যাশে না থাকে তবে এটি উপলব্ধ হওয়ার আগে এটি কয়েকশত চক্র হতে পারে।

একটি সাধারণ ফাংশন কল যখন সিপিইউ নতুন ফাংশনের প্রথম নির্দেশটি আনবে এবং এটি ক্যাশে নেই তখন কোনও নির্দেশনা ক্যাশে মিস তৈরি করতে পারে।

একটি ভার্চুয়াল ফাংশন কলের প্রথমে অবজেক্ট থেকে ভেটেবল পয়েন্টারটি লোড করা দরকার। এটি একটি ডেটা ক্যাশে মিস এর ফলস্বরূপ। তারপরে এটি ভিটিবেল থেকে ফাংশন পয়েন্টার লোড করে যার ফলে অন্য ডেটা ক্যাশে মিস হতে পারে। তারপরে এটি সেই ফাংশনটিকে কল করে যার ফলে কোনও অনু-ভার্চুয়াল ফাংশনের মতো নির্দেশের ক্যাশে মিস হতে পারে।

অনেক ক্ষেত্রে, দুটি অতিরিক্ত ক্যাশে মিস করা কোনও উদ্বেগ নয়, তবে কার্য সম্পাদনের সমালোচনামূলক কোডের একটি শক্ত লুপে এটি নাটকীয়ভাবে কর্মক্ষমতা হ্রাস করতে পারে।


6
ডান, তবে যে কোনও কোড (বা vtable) যা বারবার বলা হয় শক্ত লুপ থেকে (অবশ্যই) খুব কমই ক্যাশে মিস করবে suffer তদুপরি, ভিটিবেল পয়েন্টারটি সাধারণত একই ক্যাশে লাইনে অবজেক্টের অন্যান্য ডেটার মতো থাকে যা ডাকা পদ্ধতিটি অ্যাক্সেস করবে, তাই প্রায়শই আমরা কেবল একটি অতিরিক্ত ক্যাশে মিসের কথা বলি।
কিওয়ারটি

5
@ কিওয়ার্টি আমি এটি প্রয়োজনীয় সত্য বলে মনে করি না। লুপের বডি (যদি L1 ক্যাশে-এর চেয়ে বড় হয়) ভিটিবেল পয়েন্টার, ফাংশন পয়েন্টার এবং পরবর্তী পুনরাবৃত্তিকে প্রতিটি পুনরাবৃত্তিতে L2 ক্যাশে (বা আরও) অ্যাক্সেসের জন্য অপেক্ষা করতে হবে
গীতা

30

আগ্নার ফগের "সি ++ এ অনুকূলিতকরণ সফ্টওয়্যার" এর ম্যানুয়ালটির 44 পৃষ্ঠা থেকে :

ভার্চুয়াল সদস্য ফাংশনটি কল করতে যে সময় লাগে এটি হ'ল একটি ভার্চুয়াল সদস্য ফাংশনটি কল করার চেয়ে কয়েক ঘড়ি চক্র, শর্ত থাকে যে ফাংশন কল স্টেটমেন্ট সর্বদা ভার্চুয়াল ফাংশনের একই সংস্করণটিকে কল করে। যদি সংস্করণটি পরিবর্তন হয় তবে আপনি 10 - 30 ঘড়ির চক্রের একটি ভুল অনুমানের জরিমানা পাবেন। ভার্চুয়াল ফাংশন কলগুলির পূর্বাভাস এবং ভুল অনুমানের নিয়মগুলি স্যুইচ স্টেটমেন্টের মতোই ...


এই রেফারেন্সের জন্য ধন্যবাদ। অ্যাগ্রনার ফগের অপ্টিমাইজেশান ম্যানুয়াল হ'ল সর্বোত্তমভাবে হার্ডওয়্যার ব্যবহারের জন্য সোনার মান।
আর্টো বেনডিকেন

আমার স্মরণে এবং দ্রুত অনুসন্ধানের উপর ভিত্তি করে - stackoverflow.com/questions/17061967/c-switch-and-jump-tables - আমি সন্দেহ করি যে এটি সর্বদা সত্য switch। সম্পূর্ণ নির্বিচারে caseমান সহ, নিশ্চিত। তবে সবগুলি যদি caseধারাবাহিক হয় তবে একটি সংকলক এটিকে একটি জাম্প-টেবিলের মধ্যে অনুকূল করতে সক্ষম হতে পারে (আহ, যা আমাকে ভাল পুরানো জেড 80 দিনের স্মরণ করিয়ে দেয়), যা হওয়া উচিত (আরও ভাল সময়ের জন্য) ধ্রুবক সময় হওয়া উচিত। এমন নয় যে আমি vfuncs এর সাথে প্রতিস্থাপনের চেষ্টা করব switch, যা হাস্যকর। ;)
আন্ডারস্কোর_

7

একেবারে। কম্পিউটারগুলি 100 মেগাহার্টজ চলাকালীন এটি ফিরে আসা সমস্যা ছিল, কারণ প্রতিটি পদ্ধতির কলটির জন্য ভিটিবেল কল করার আগে এটি দেখার প্রয়োজন ছিল। কিন্তু আজ .. একটি 3Ghz সিপিইউতে আমার প্রথম কম্পিউটারের চেয়ে বেশি মেমরির সাথে প্রথম স্তরের ক্যাশে রয়েছে? একেবারেই না. প্রধান র‌্যাম থেকে মেমরি বরাদ্দ করতে আপনার সমস্ত ফাংশন ভার্চুয়াল ছিল না তার চেয়ে বেশি সময় লাগবে।

এটি পুরানো, পুরানো দিনের মতো যেখানে লোকেরা বলেছিল কাঠামোগত প্রোগ্রামিং ধীর ছিল কারণ সমস্ত কোডকে ফাংশনে বিভক্ত করা হয়েছিল, প্রতিটি ফাংশনটির জন্য স্ট্যাক বরাদ্দ এবং একটি ফাংশন কল প্রয়োজন!

আমি কেবল ভার্চুয়াল ফাংশনটির পারফরম্যান্স প্রভাব বিবেচনা করতে বিরক্ত করার কথা ভাবব না, যদি এটি খুব ভারী ব্যবহার করা হত এবং টেম্প্লেটেড কোডে ইনস্ট্যান্ট করা হত যা সমস্ত কিছুতেই শেষ হয়ে গিয়েছিল। তারপরেও, আমি এটিতে খুব বেশি প্রচেষ্টা ব্যয় করব না!

পিএস অন্যান্য 'সহজেই ব্যবহারযোগ্য ভাষা' ভাবেন - তাদের সমস্ত পদ্ধতি কভারগুলির নিচে ভার্চুয়াল এবং সেগুলি আজকাল ক্রল হয় না।


4
ভাল, আজও উচ্চ-পারফ্যাক্স অ্যাপ্লিকেশনগুলির জন্য ফাংশন কলগুলি এড়ানো গুরুত্বপূর্ণ। পার্থক্যটি হ'ল, আজকের সংকলকগুলি নির্ভরযোগ্যভাবে ছোট ফাংশনগুলিকে ইনলাইন করে যাতে আমরা ছোট ফাংশনগুলি লেখার জন্য গতির শাস্তি ভোগ করি না। ভার্চুয়াল ফাংশন হিসাবে, স্মার্ট সিপিইউগুলি তাদের উপর স্মার্ট শাখার পূর্বাভাস দিতে পারে। পুরানো কম্পিউটারগুলি ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে নাম উঠতে পারে। 1992-এ যদি আমরা একটি এমপি 3 খেলি তবে আমরা জানতাম যে আমাদের হয়ত অর্ধেকেরও বেশি সিপিইউ সেই কাজের জন্য উত্সর্গ করতে হবে।
কিওয়ারটি

6
এমপি 3 তারিখ 1995 সালের তারিখের। 92-এ আমাদের সবেমাত্র 386 ছিল, তারা কোনও এমপি 3 খেলতে পারে না, এবং সিপিইউ সময়ের 50% একটি ভাল মাল্টি টাস্ক ওএস, একটি নিষ্ক্রিয় প্রক্রিয়া এবং একটি পূর্বসূচি নির্ধারণকারী হিসাবে ধরে নিয়েছে। এগুলির কোনওটিই সে সময় গ্রাহক বাজারে বিদ্যমান ছিল না। গল্পটি শেষ হওয়ার মুহুর্ত থেকে এটি 100% ছিল।
v.oddou

7

ফাঁসির সময় ছাড়াও আরও একটি পারফরম্যান্স মানদণ্ড রয়েছে। একটি Vtable মেমরির স্থানও গ্রহণ করে এবং কিছু ক্ষেত্রে এড়ানো যায়: এটিএল সংকলন-সময় " সিমুলেটেড ডায়নামিক বাইন্ডিং ব্যবহার করে " ব্যবহার করে টেমপ্লেটগুলি ব্যবহার করে"স্ট্যাটিক পলিমারফিজম" এর প্রভাব পেতে, যা ব্যাখ্যা করা একরকম কঠিন; আপনি মূলত একটি বর্গ শ্রেণীর টেম্পলেটে প্যারামিটার হিসাবে উত্পন্ন ক্লাসটি পাস করেন, সুতরাং সংকলন করার সময় বেস ক্লাসটি প্রতিটি উদাহরণে তার উত্পন্ন ক্লাসটি কী তা "জানে"। বেস ধরণের (যা রান-টাইম পলিমারফিজম) সংগ্রহের ক্ষেত্রে আপনাকে একাধিক ভিন্ন উত্সযুক্ত ক্লাসগুলি সংরক্ষণ করতে দেবে না তবে স্থির অর্থে যদি আপনি কোনও ক্লাস ওয়াই করতে চান যা প্রাইসিং টেম্পলেট ক্লাস এক্স এর সমান এই জাতীয় ওভাররাইডিংয়ের জন্য হুকগুলি, আপনার কেবল নিজের যত্ন নেওয়া পদ্ধতিগুলি ওভাররাইড করা দরকার এবং তারপরে আপনি কোনও ভিটিবেল না করে দশম শ্রেণির বেস পদ্ধতিগুলি পেয়ে যান।

বড় মেমরির পদচিহ্নগুলির সাথে ক্লাসগুলিতে, একক ভিটিবল পয়েন্টারের দাম খুব বেশি নয়, তবে সিওএম-এর কিছু এটিএল ক্লাস খুব ছোট এবং রান-টাইম পলিমারফিজম কেস কখনই ঘটতে চলেছে না, তবে এটি ভিটিবেল সঞ্চয় মূল্য।

আরও দেখুন অন্য তাই প্রশ্ন

যাইহোক এখানে আমি একটি পোস্টিং খুঁজে পেয়েছি যে সিপিইউ-সময়ের পারফরম্যান্সের দিকগুলি নিয়ে কথা বলে।



4

হ্যাঁ, আপনি ঠিক বলেছেন এবং ভার্চুয়াল ফাংশন কলটির দাম সম্পর্কে আগ্রহী হলে আপনি এই পোস্টটিকে আকর্ষণীয় বলে মনে করতে পারেন find


1
লিঙ্কযুক্ত নিবন্ধটি ভার্চুয়াল কলের খুব গুরুত্বপূর্ণ অংশ বিবেচনা করে না এবং এটিই সম্ভবত শাখার ভুল ধারণা।
সুমা

4

একমাত্র উপায় যে আমি দেখতে পাচ্ছি যে ভার্চুয়াল ফাংশনটি একটি পারফরম্যান্স সমস্যা হয়ে উঠবে তা হ'ল যদি অনেক ভার্চুয়াল ফাংশন একটি টান লুপের মধ্যে ডাকা হয়, এবং যদি এবং কেবল যদি একটি ভারী তারা কোনও পৃষ্ঠা ত্রুটি বা অন্যান্য "ভারী" মেমরি অপারেশন ঘটায়।

যদিও অন্যান্য লোকেরা বলেছে এটি বাস্তব জীবনে আপনার পক্ষে কখনও সমস্যা হবেনা। এবং যদি আপনি মনে করেন যে এটি একজন প্রোফাইলার চালান, কিছু পরীক্ষা করে দেখুন এবং পারফরম্যান্স সুবিধার জন্য আপনার কোডটি "ডিজাইন্ড" করার চেষ্টা করার আগে এটি সত্যিই কোনও সমস্যা কিনা তা যাচাই করুন।


2
কোনও শক্ত লুপে কোনও কল করা সম্ভবত সমস্ত কোড এবং ডেটা গরম করে রাখবে ক্যাশে ...
গ্রেগ রজার্স

2
হ্যাঁ, তবে যদি সেই ডান লুপটি অবজেক্টগুলির তালিকার মাধ্যমে পুনরাবৃত্তি করে তবে প্রতিটি বস্তুটি একই ফাংশন কলের মাধ্যমে একটি পৃথক ঠিকানায় ভার্চুয়াল ফাংশনটিকে কল করতে পারে।
দাইমিন

3

যখন শ্রেণি পদ্ধতিটি ভার্চুয়াল নয়, সংকলক সাধারণত ইন-আস্তরণ করে। বিপরীতে, যখন আপনি ভার্চুয়াল ফাংশন সহ কোনও শ্রেণিতে পয়েন্টার ব্যবহার করেন, আসল ঠিকানাটি কেবল রানটাইমেই জানা যাবে।

এটি পরীক্ষা, সময়ের পার্থক্য well 700% (!) দ্বারা ভালভাবে ফুটিয়ে তোলা হয়েছে:

#include <time.h>

class Direct
{
public:
    int Perform(int &ia) { return ++ia; }
};

class AbstrBase
{
public:
    virtual int Perform(int &ia)=0;
};

class Derived: public AbstrBase
{
public:
    virtual int Perform(int &ia) { return ++ia; }
};


int main(int argc, char* argv[])
{
    Direct *pdir, dir;
    pdir = &dir;

    int ia=0;
    double start = clock();
    while( pdir->Perform(ia) );
    double end = clock();
    printf( "Direct %.3f, ia=%d\n", (end-start)/CLOCKS_PER_SEC, ia );

    Derived drv;
    AbstrBase *ab = &drv;

    ia=0;
    start = clock();
    while( ab->Perform(ia) );
    end = clock();
    printf( "Virtual: %.3f, ia=%d\n", (end-start)/CLOCKS_PER_SEC, ia );

    return 0;
}

ভার্চুয়াল ফাংশন কলের প্রভাব পরিস্থিতির উপর নির্ভর করে। যদি ফাংশনের অভ্যন্তরে কয়েকটি কল এবং উল্লেখযোগ্য পরিমাণে কাজের কাজ থাকে - তবে তা নগদ হতে পারে।

বা, যখন এটি কোনও ভার্চুয়াল কলটি বার বার ব্যবহৃত হয় যখন কিছু সাধারণ অপারেশন করা হয় - এটি সত্যিই বড় হতে পারে।


4
তুলনায় একটি ভার্চুয়াল ফাংশন কল ব্যয়বহুল ++ia। তাতে কি?
বো পারসন

2

আমি আমার বিশেষ প্রকল্পে কমপক্ষে 20 বার পিছনে পিছনে গিয়েছি। যদিও পারেন কোড পুনঃব্যবহারের, স্বচ্ছতা, maintainability এবং পাঠযোগ্যতা পরিপ্রেক্ষিতে কিছু মহান লাভ হতে অন্যদিকে কর্মক্ষমতা হিট এখনও কি থাকবেই ভার্চুয়াল ফাংশন সঙ্গে।

একটি আধুনিক ল্যাপটপ / ডেস্কটপ / ট্যাবলেটে পারফরম্যান্সটি লক্ষণীয় হতে চলেছে ... সম্ভবত তা নয়! তবে এম্বেড থাকা সিস্টেমগুলির সাথে কিছু ক্ষেত্রে পারফরম্যান্স হিট হতে পারে আপনার কোডের অদক্ষতার জন্য ড্রাইভিং ফ্যাক্টর, বিশেষত যদি ভার্চুয়াল ফাংশনটিকে বারবার ডেকে আনা হয়।

এম্বেড থাকা সিস্টেমের প্রসঙ্গে সি / সি +++ এর জন্য সেরা যা অনুশীলনগুলি অ্যানেলিজ করে তা এখানে দেওয়া হয়েছে: http://www.open-std.org/jtc1/sc22/wg21/docs/ESC_Boston_01_304_paper.pdf

উপসংহারে: অন্যটির উপর একটি নির্দিষ্ট নির্মাণ ব্যবহারের উপকারিতা / ধারণাগুলি বুঝতে এটি প্রোগ্রামারটির উপর নির্ভর করে। আপনি যদি সুপার পারফরম্যান্স দ্বারা চালিত না হন তবে আপনি সম্ভবত পারফরম্যান্স হিটের বিষয়ে চিন্তা করবেন না এবং আপনার কোডটি যতটা সম্ভব ব্যবহারযোগ্য করে তুলতে সহায়তা করার জন্য সি ++ তে সমস্ত ঝরঝরে OO স্টাফ ব্যবহার করা উচিত।


2

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


1

একটি বিষয় লক্ষণীয় তা হ'ল:

boolean contains(A element) {
    for (A current: this)
        if (element.equals(current))
            return true;
    return false;
}

এর চেয়ে দ্রুত হতে পারে:

boolean contains(A element) {
    for (A current: this)
        if (current.equals(equals))
            return true;
    return false;
}

এটি কারণ প্রথম পদ্ধতিটি কেবল একটি ফাংশনকে কল করছে যখন দ্বিতীয়টি হয়ত বিভিন্ন ফাংশন কল করে। এটি কোনও ভাষার কোনও ভার্চুয়াল ফাংশনে প্রযোজ্য।

আমি "মে" বলি কারণ এটি সংকলক, ক্যাশে ইত্যাদির উপর নির্ভর করে


0

ভার্চুয়াল ফাংশনগুলি ব্যবহারের পারফরম্যান্স জরিমানা কখনই আপনার নকশা স্তরে পাওয়া সুবিধাগুলি ওজন করতে পারে না weight ধারণা করা যায় ভার্চুয়াল ফাংশনে একটি কল 25% কম দক্ষ হবে তবে স্থির ফাংশনে সরাসরি কল। ভিএমটি-র মাধ্যমে ইন্ডায়ারেশনের একটি স্তর রয়েছে বলে এটি ঘটে। তবে কল করার জন্য নেওয়া সময়টি সাধারণত আপনার ক্রিয়াকলাপের প্রকৃত বাস্তবায়নের সময়টির তুলনায় খুব অল্প হয় তাই মোট পারফরম্যান্স ব্যয়টি বিশেষত হার্ডওয়্যারের বর্তমান পারফরম্যান্সের সাথে অবহেলাযোগ্য হবে। তদাতিরিক্ত সংকলকটি মাঝে মধ্যে অনুকূলিত করতে পারে এবং দেখতে পারে যে কোনও ভার্চুয়াল কলের প্রয়োজন নেই এবং এটি একটি স্ট্যাটিক কলটিতে সংকলন করে। সুতরাং ভার্চুয়াল ফাংশন এবং অ্যাবস্ট্রাক্ট ক্লাসগুলি আপনার প্রয়োজন অনুযায়ী ব্যবহার করার চিন্তা করবেন না।


2
কখনই না, লক্ষ্য কম্পিউটার কতটা ছোট?
জুমালাইফগার্ড

আপনি যদি এই কথাটি উচ্চারণ করেন তবে আমি সম্মত হয়েছি যে The performance penalty of using virtual functions can sometimes be so insignificant that it is completely outweighed by the advantages you get at the design level.মূল পার্থক্যটি বলছে sometimes, তা নয় never
আন্ডারস্কোর_২০

-1

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

আজ আমার সিদ্ধান্ত নিতে হয়েছিল আমার বাফার ক্লাসে আরও মেমরি বরাদ্দ করার জন্য ভার্চুয়াল ফাংশনটি ব্যবহার করতে হবে কি না, খুব কার্য সম্পাদনের সমালোচনামূলক অ্যাপে, তাই আমি গুগল করেছিলাম (এবং আপনাকে খুঁজে পেয়েছি) এবং শেষ পর্যন্ত আবার পরীক্ষাও করেছিলাম।

// g++ -std=c++0x -o perf perf.cpp -lrt
#include <typeinfo>    // typeid
#include <cstdio>      // printf
#include <cstdlib>     // atoll
#include <ctime>       // clock_gettime

struct Virtual { virtual int call() { return 42; } }; 
struct Inline { inline int call() { return 42; } }; 
struct Normal { int call(); };
int Normal::call() { return 42; }

template<typename T>
void test(unsigned long long count) {
    std::printf("Timing function calls of '%s' %llu times ...\n", typeid(T).name(), count);

    timespec t0, t1;
    clock_gettime(CLOCK_REALTIME, &t0);

    T test;
    while (count--) test.call();

    clock_gettime(CLOCK_REALTIME, &t1);
    t1.tv_sec -= t0.tv_sec;
    t1.tv_nsec = t1.tv_nsec > t0.tv_nsec
        ? t1.tv_nsec - t0.tv_nsec
        : 1000000000lu - t0.tv_nsec;

    std::printf(" -- result: %d sec %ld nsec\n", t1.tv_sec, t1.tv_nsec);
}

template<typename T, typename Ua, typename... Un>
void test(unsigned long long count) {
    test<T>(count);
    test<Ua, Un...>(count);
}

int main(int argc, const char* argv[]) {
    test<Inline, Normal, Virtual>(argc == 2 ? atoll(argv[1]) : 10000000000llu);
    return 0;
}

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


12
আমি মনে করি এটি সম্ভবত আপনার সংকলকটি বলতে পারে যে আপনার কোডের ভার্চুয়াল ফাংশন কলটি কেবল ভার্চুয়াল :: কল করতে পারে। সেক্ষেত্রে এটি কেবল এটিকে ইনলাইন করতে পারে। সংকলকটিকে সাধারণ :: কল করার জন্য ইনলাইন করা থেকে বাধা দেওয়ার মতো কিছু নেই you সুতরাং আমি মনে করি যে 3 টি ক্রিয়াকলাপের জন্য আপনি একই সময়টি পান এটি বেশ সম্ভব কারণ সংকলক তাদের জন্য অভিন্ন কোড উত্পন্ন করছে।
বজর্কে এইচ। রোনে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.