সি ++ 11 এ অ্যাসিঙ্ক (লঞ্চ :: অ্যাসিঙ্ক) ব্যয়বহুল থ্রেড সৃষ্টি এড়ানোর জন্য থ্রেড পুলগুলি অপ্রচলিত করে?


117

এটি এই প্রশ্নের সাথে শিথিলভাবে সম্পর্কিত: এসটিডি :: থ্রেডটি কি সি ++ 11 তে পুল করা হয়? । যদিও প্রশ্নটি পৃথক, উদ্দেশ্য একই:

প্রশ্ন 1: ব্যয়বহুল থ্রেড সৃষ্টি এড়াতে এখনও নিজের (বা তৃতীয় পক্ষের লাইব্রেরি) থ্রেড পুলগুলি ব্যবহার করা কি বোধগম্য?

অন্যান্য প্রশ্নের উপসংহারটি হ'ল আপনি std::threadপুল করার উপর নির্ভর করতে পারবেন না (এটি হতে পারে বা এটি হতে পারে না)। তবে std::async(launch::async)মনে হচ্ছে পুলে যাওয়ার অনেক বেশি সুযোগ রয়েছে।

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

প্রশ্ন 2: এটি আমি যা মনে করি ঠিক এটি তবে এটি প্রমাণ করার মতো আমার কাছে কোনও তথ্য নেই। আমি খুব ভাল ভুল হতে পারে। এটা কি শিক্ষিত অনুমান?

অবশেষে, আমি এখানে কিছু নমুনা কোড সরবরাহ করেছি যা প্রথম দেখায় যে আমি কীভাবে থ্রেড তৈরির দ্বারা প্রকাশ করতে পারি বলে মনে করি async(launch::async):

উদাহরণ 1:

 thread t([]{ f(); });
 // ...
 t.join();

হয়ে

 auto future = async(launch::async, []{ f(); });
 // ...
 future.wait();

উদাহরণ 2: আগুন এবং থ্রেড ভুলে যান

 thread([]{ f(); }).detach();

হয়ে

 // a bit clumsy...
 auto dummy = async(launch::async, []{ f(); });

 // ... but I hope soon it can be simplified to
 async(launch::async, []{ f(); });

প্রশ্ন 3: আপনি asyncসংস্করণ সংস্করণ পছন্দ করবেন thread?


বাকিগুলি এখন আর প্রশ্নের অংশ নয়, তবে কেবল স্পষ্ট করার জন্য:

ফেরতের মানটি একটি ডামি ভেরিয়েবলের জন্য কেন বরাদ্দ করা উচিত?

দুর্ভাগ্যক্রমে, বর্তমান সি ++ 11 স্ট্যান্ডার্ড বাহিনী std::asyncযেগুলির আপনি ফেরতের মানটি ক্যাপচার করেন , অন্যথায় ধ্বংসকারী কার্যকর করা হয়, যা ক্রিয়া শেষ না হওয়া অবধি অবরুদ্ধ করে। এটি কিছুকে স্ট্যান্ডার্ডের একটি ত্রুটি হিসাবে বিবেচনা করা হয় (উদাঃ, হার্ব সাটার দ্বারা)।

Cppreferences.com এর এই উদাহরণটি এটিকে সুন্দরভাবে ফুটিয়ে তুলেছে :

{
  std::async(std::launch::async, []{ f(); });
  std::async(std::launch::async, []{ g(); });  // does not run until f() completes
}

আরেকটি ব্যাখ্যা:

আমি জানি যে থ্রেড পুলগুলির অন্যান্য বৈধ ব্যবহার থাকতে পারে তবে এই প্রশ্নে আমি ব্যয়বহুল থ্রেড তৈরির ব্যয় এড়াতে কেবল আগ্রহী

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

থ্রেড-স্থানীয় ভেরিয়েবলগুলি আপনার নিজস্ব থ্রেড পুলগুলির পক্ষেও একটি যুক্তি হতে পারে, তবে এটি অনুশীলনে প্রাসঙ্গিক কিনা তা আমি নিশ্চিত নই:

  • std::threadপ্রারম্ভিক থ্রেড-স্থানীয় ভেরিয়েবলগুলি ছাড়াই শুরু করে একটি নতুন থ্রেড তৈরি করা । সম্ভবত এটি আপনি চান না।
  • থ্রেডগুলি দ্বারা প্রসারিত async, এটি আমার পক্ষে কিছুটা অস্পষ্ট কারণ থ্রেডটি পুনরায় ব্যবহার করা যেতে পারে। আমার উপলব্ধি থেকে, থ্রেড-স্থানীয় ভেরিয়েবলগুলি পুনরায় সেট করার গ্যারান্টি নেই তবে আমার ভুল হতে পারে।
  • অন্যদিকে আপনার নিজের (স্থির-আকারের) থ্রেড পুলগুলি ব্যবহার করা আপনাকে যদি সত্যই এটির প্রয়োজন হয় তবে আপনাকে সম্পূর্ণ নিয়ন্ত্রণ দেয়।

8
"তবে std::async(launch::async)মনে হচ্ছে পুলে যাওয়ার অনেক বেশি সুযোগ রয়েছে।" না, আমি বিশ্বাস করি এটি std::async(launch::async | launch::deferred)পুলে যেতে পারে। launch::asyncঅন্যান্য কাজগুলি যা চলছে তা নির্ধারণ না করে সবেমাত্র একটি নতুন থ্রেডে টাস্কটি চালু করার কথা রয়েছে। নীতিটি নিয়ে launch::async | launch::deferredতারপরে বাস্তবায়নটি কোন নীতিটি চয়ন করতে পারে, তবে আরও গুরুত্বপূর্ণটি হ'ল কোন নীতিটি বেছে নিতে বিলম্ব হয়। এটি, থ্রেড পুলে একটি থ্রেড উপলব্ধ না হওয়া পর্যন্ত এটি অপেক্ষা করতে পারে এবং তারপরে অ্যাসিঙ্ক নীতিটি চয়ন করতে পারে।
bames53

2
আমি যতদূর জানি কেবল ভিসি ++ এর সাথে একটি থ্রেড পুল ব্যবহার করে std::async()। তারা এখনও থ্রেড পুলে অ-তুচ্ছ থ্রেড_লোকাল ডেস্ট্রাক্টরকে কীভাবে সমর্থন করে তা দেখতে আমি এখনও আগ্রহী।
bames53

2
@ বেমস ৫৩ আমি জিবিসি ৪.7.২ সহ লাইবস্টিডি ++ দিয়ে পা রেখেছি এবং দেখেছি যে লঞ্চ পলিসিটি ঠিক না launch::asyncথাকলে এটি কেবল এটির মতো আচরণ করে launch::deferredএবং কখনই এটি অযৌক্তিকভাবে কার্যকর করে না - ফলস্বরূপ, libstdc এর সংস্করণ ++ "চয়ন করে" অন্যথায় বাধ্য না করা হলে সর্বদা পিছিয়ে থাকা ব্যবহার করতে।
doug65536

3
@ doug65536 থ্রেড_লোকাল ডেস্ট্রাক্টর সম্পর্কে আমার বক্তব্যটি থ্রেড পুল ব্যবহার করার সময় থ্রেড প্রস্থান করার সময় ধ্বংসটি বেশ সঠিক নয়। কোনও কাজ যখন অবিচ্ছিন্নভাবে চালানো হয় তখন অনুমান অনুসারে এটি 'নতুন থ্রেডের মতো' চালিত হয়, যার অর্থ প্রতিটি অ্যাসিঙ্ক টাস্কের নিজস্ব থ্রেড_লোক্যাল অবজেক্ট হয়। একই ব্যাকিং থ্রেড ভাগ করে নেওয়া কাজগুলি এখনও তাদের থ্রেড_লোকাল অবজেক্টের মতো আচরণ করে তা নিশ্চিত করার জন্য একটি থ্রেড পুল ভিত্তিক বাস্তবায়নকে বিশেষ যত্ন নিতে হবে। এই প্রোগ্রামটি বিবেচনা করুন: পেস্টবিন.
com

2
@ বেমস ৫৩ স্পেকটিতে "যেন নতুন থ্রেডে" ব্যবহার করা আমার মতে একটি বিশাল ভুল ছিল । std::asyncপারফরম্যান্সের জন্য একটি সুন্দর জিনিস হতে পারে - এটি স্ট্যান্ডার্ড পুলের সাহায্যে স্বাভাবিকভাবে সমর্থিত স্ট্যান্ডার্ড শর্ট-রানিং-টাস্ক এক্সিকিউশন সিস্টেম হতে পারে। এই মুহুর্তে, std::threadথ্রেড ফাংশনটি কোনও মান ফেরত দিতে সক্ষম করতে এটি কিছু ক্রেপ সঙ্গে সজ্জিত। ওহ, এবং তারা রিডানড্যান্ট "মুলতুবি" কার্যকারিতা যুক্ত করেছে যা std::functionপুরোপুরিভাবে কাজকে ওভারল্যাপ করে ।
doug65536

উত্তর:


54

প্রশ্ন 1 :

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

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

আইএমএইচও, লিনাক্স কার্নেলের লোকেরা থ্রেড তৈরির কাজটি এখনকার চেয়ে সস্তা তৈরিতে কাজ করা উচিত। তবে, স্ট্যান্ডার্ড সি ++ গ্রন্থাগারটি প্রয়োগ করার জন্য পুল ব্যবহার করাও বিবেচনা করা উচিত launch::async | launch::deferred

এবং ওপি সঠিক, ::std::threadঅবশ্যই একটি থ্রেড চালু করতে পুল থেকে একটি ব্যবহার না করে একটি নতুন থ্রেড তৈরি করতে বাধ্য করে। তাই ::std::async(::std::launch::async, ...)পছন্দ করা হয়।

প্রশ্ন 2 :

হ্যাঁ, মূলত এই 'অন্তর্নিহিত' একটি থ্রেড চালু করে। তবে আসলে কী ঘটছে তা এখনও স্পষ্ট। সুতরাং আমি প্রকৃতপক্ষে শব্দটি বিশেষত একটি ভাল শব্দ বলে মনে করি না।

আমিও নিশ্চিত নই যে ধ্বংসের আগে আপনাকে ফেরতের জন্য অপেক্ষা করতে বাধ্য করা অবশ্যই একটি ত্রুটি। আমি জানি না যে আপনি async'ডেমন' থ্রেডগুলি তৈরি করতে কলটি ব্যবহার করবেন যা প্রত্যাশিত প্রত্যাশিত নয়। এবং যদি তাদের প্রত্যাশার প্রত্যাশা থাকে তবে ব্যতিক্রমগুলি উপেক্ষা করা ঠিক হবে না।

প্রশ্ন 3 :

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

আমি 'ভবিষ্যতের' মডেলের তুলনায় কাজের কাতারের মডেলটিকে আরও অনেক ভাল পছন্দ করেছি কারণ সেখানে 'সিরিয়াল দ্বীপপুঞ্জ' রয়েছে যার ফলে আপনি আরও কার্যকরভাবে পরিবর্তনীয় স্থিতি পরিচালনা করতে পারেন।

তবে সত্যই, এটি নির্ভর করে আপনি কী করছেন।

কর্মক্ষমতা পরীক্ষা

সুতরাং, আমি জিনিসগুলি কল করার বিভিন্ন পদ্ধতির পারফরম্যান্স পরীক্ষা করেছি এবং ফেডোরা 29 চলমান একটি 8 কোর (এএমডি রাইজন 7 2700 এক্স) সিস্টেমে এই সংখ্যাগুলি নিয়ে এসেছি cla

   Do nothing calls per second:   35365257                                      
        Empty calls per second:   35210682                                      
   New thread calls per second:      62356                                      
 Async launch calls per second:      68869                                      
Worker thread calls per second:     970415                                      

এবং নেটিভ, আমার ম্যাকবুক প্রো 15 "(ইন্টেল (আর) কোর (টিএম) i7-7820HQ সিপিইউ @ 2.90GHz) Apple LLVM version 10.0.0 (clang-1000.10.44.4)ওএসএক্স 10.13.6 এর অধীনে, আমি এটি পেয়েছি:

   Do nothing calls per second:   22078079
        Empty calls per second:   21847547
   New thread calls per second:      43326
 Async launch calls per second:      58684
Worker thread calls per second:    2053775

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

"কিছুই করবেন না" কেবল পরীক্ষার জোয়ারের ওভারহেড পরীক্ষা করা।

এটি স্পষ্ট যে থ্রেড চালু করার ওভারহেডটি প্রচুর। এমনকি আন্ত-থ্রেড সারি সহ কর্মী থ্রেড 20 বা আরও একটি ফ্যাক্টর দ্বারা কোনও ভিএম-তে ফেডোরা 25 এবং দেশীয় ওএস এক্স-তে প্রায় 8 দ্বারা জিনিসকে ধীর করে দেয়

আমি পারফরম্যান্স টেস্টের জন্য কোডটি ব্যবহার করে একটি বিটবাকেট প্রকল্প তৈরি করেছি। এটি এখানে পাওয়া যাবে: https://bitbucket.org/omnifarious/launch_thread_performance


3
আমি কাজের-কাতারে মডেলটির সাথে একমত হই, তবে এর জন্য একটি "পাইপলাইন" মডেল থাকা দরকার যা একযোগে অ্যাক্সেসের প্রতিটি ব্যবহারের জন্য প্রযোজ্য নাও হতে পারে।
ম্যাথিউ এম।

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

3
"খুব সস্তা" আপনার অভিজ্ঞতার সাথে তুলনামূলক। আমার ব্যবহারের জন্য লিনাক্স থ্রেড তৈরির ওভারহেডটি যথেষ্ট বলে মনে হচ্ছে ।
জেফ

1
@ জেফ - আমি ভেবেছিলাম এটি তুলনায় অনেক সস্তা। আসল ব্যয়টি আবিষ্কার করতে আমি যে পরীক্ষার প্রতিফলন করেছি তার প্রতিফলন করতে আমি কিছুক্ষণ আগে আমার উত্তর আপডেট করেছি।
সর্বসম্মত

4
প্রথম অংশে, আপনি কিছুটা হুমকি তৈরি করতে কতটা করতে হবে এবং কোনও ফাংশন ডাকতে কতটুকু কাজ করতে হবে তা হ্রাস করা হচ্ছে না। একটি ফাংশন কল এবং রিটার্ন হ'ল কয়েকটি সিপিইউ নির্দেশনা যা স্ট্যাকের শীর্ষে কয়েকটি বাইট চালিত করে। হুমকি সৃষ্টির অর্থ: ১. স্ট্যাক বরাদ্দ করা, ২. একটি সিস্কেল সম্পাদন করা, ৩. কার্নেলের মধ্যে ডেটা স্ট্রাকচার তৈরি করা এবং সেগুলি সংযুক্ত করা, পথের সাথে তালা আঁকানো, ৪. সূচীটি থ্রেডটি কার্যকর করার জন্য অপেক্ষা করা, ৫. পরিবর্তন থ্রেড প্রসঙ্গে। এই প্রতিটি পদক্ষেপ নিজেই সবচেয়ে জটিল ফাংশন কলগুলির চেয়ে অনেক বেশি সময় নেয় ।
মাস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.