থ্রেডিং এবং মাল্টিপ্রসেসিং মডিউলগুলির মধ্যে পার্থক্যগুলি কী কী?


141

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

কোনও threading.Thread()বস্তু এবং multiprocessing.Process()একজনের মধ্যে পার্থক্য কী তা বোঝার জন্য আমি এটিকে কঠিনভাবে খুঁজে পাচ্ছি (সম্ভবত এটি সম্পর্কে আমার কোনও তাত্ত্বিক পটভূমি নেই) to

এছাড়াও, আমার কাছে কীভাবে একটি কাজের সারির তাত্পর্য স্থাপন করা যায় এবং তাদের মধ্যে কেবল 4 টি (উদাহরণস্বরূপ) সমান্তরালভাবে চলতে হবে তা সম্পূর্ণভাবে পরিষ্কার নয়, অন্যরা মৃত্যুদন্ড কার্যকর হওয়ার আগে অন্যান্য সংস্থাগুলি মুক্ত হওয়ার অপেক্ষায় রয়েছে।

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

সুতরাং, আমি কখন threadingএবং multiprocessingমডিউলগুলি ব্যবহার করব ?

আপনি কি আমাকে এমন কিছু সংস্থার সাথে লিঙ্ক করতে পারেন যা এই দুটি মডিউলের পিছনে ধারণাগুলি এবং কীভাবে জটিল কাজের জন্য এগুলি সঠিকভাবে ব্যবহার করতে পারে তার ব্যাখ্যা দেয়?


আরও রয়েছে, মডিউলটিও রয়েছে Thread( _threadপাইথন 3.x নামে পরিচিত )। সত্যি কথা বলতে কি আমি নিজের মধ্যে পার্থক্যগুলি কখনই বুঝতে পারি নি ...
ডুন্নো

3
@Dunno: হিসাবে Thread/ _threadডকুমেন্টেশন স্পষ্টভাবে বলছেন, এটা এর "নিম্ন স্তরের প্রিমিটিভের"। আপনি নির্মাণ কাস্টম সিঙ্ক্রোনাইজেশন বস্তু করার জন্য এটি ব্যবহার করতে পারেন, থ্রেড, ইত্যাদি একটি গাছ ক্রম যোগদানের নিয়ন্ত্রণ করতে আপনি কল্পনা না পারেন, তাহলে কেন আপনি তা ব্যবহার করতে হবে চাই, এটি এবং লাঠি ব্যবহার করবেন না সঙ্গে threading
অবতারিত

উত্তর:


260

জিউলিও ফ্রাঙ্কো যা বলে তা সাধারণভাবে মাল্টিথ্রেডিং বনাম মাল্টিপ্রসেসিংয়ের ক্ষেত্রে সত্য ।

তবে পাইথন * এর একটি যুক্ত সমস্যা রয়েছে: এখানে একটি গ্লোবাল ইন্টারপ্রেটার লক রয়েছে যা একই প্রক্রিয়াতে দুটি থ্রেড একই সাথে পাইথন কোড চালানো থেকে বাধা দেয়। এর অর্থ হ'ল যদি আপনার কাছে 8 টি কোর থাকে এবং 8 টি থ্রেড ব্যবহারের জন্য আপনার কোড পরিবর্তন করে তবে এটি 800% সিপিইউ ব্যবহার করতে সক্ষম হবে না এবং 8x দ্রুত চালাতে পারবে না; এটি একই 100% সিপিইউ ব্যবহার করবে এবং একই গতিতে চলবে। (বাস্তবে, এটি কিছুটা ধীর গতিতে চলবে, কারণ থ্রেডিং থেকে অতিরিক্ত ওভারহেড রয়েছে, যদিও আপনার কাছে কোনও ভাগ করা ডেটা না থাকলেও, আপাতত এটিকে উপেক্ষা করুন))

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

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

তবে আপনি যদি খাঁটি পাইথনে সিপিইউ-বাউন্ড প্রোগ্রাম লিখছেন তবে আরও থ্রেড ব্যবহার করা সাধারণত কার্যকর হয় না।

পৃথক প্রক্রিয়াগুলি ব্যবহার করে জিআইএল-তে কোনও সমস্যা নেই, কারণ প্রতিটি প্রক্রিয়াটির নিজস্ব পৃথক জিআইএল রয়েছে। অবশ্যই আপনার কাছে থ্রেড এবং প্রক্রিয়াগুলির মধ্যে অন্য যে কোনও ভাষার মতো একই বাণিজ্য রয়েছে threads থ্রেডের মধ্যে প্রক্রিয়াগুলির মধ্যে ডেটা ভাগ করা আরও কঠিন এবং ব্যয়বহুল, বিশাল সংখ্যক প্রক্রিয়া চালানো বা তৈরি করা এবং ধ্বংস করা ব্যয়বহুল হতে পারে এগুলি ঘন ঘন ইত্যাদি But কিন্তু জিআইএল প্রক্রিয়াগুলির প্রতি ভারসাম্যের উপর খুব বেশি ওজন করে a এমন উপায়ে যা সি বা জাভার পক্ষে সত্য নয় say সুতরাং, আপনি সি বা জাবার চেয়ে পাইথনে বহুবার মাল্টিপ্রসেসিং ব্যবহার করছেন।


এদিকে পাইথনের "ব্যাটারি অন্তর্ভুক্ত" দর্শন কিছু সুসংবাদ এনেছে: কোডটি লেখা খুব সহজ যে এক-লাইনের পরিবর্তনের মাধ্যমে থ্রেড এবং প্রক্রিয়াগুলির মধ্যে পিছনে পিছনে পরিবর্তন করা যায়।

আপনি যদি নিজের কোডটি স্ব-অন্তর্ভুক্ত "কাজের" পদে ডিজাইন করেন যা ইনপুট এবং আউটপুট ব্যতীত অন্য কাজের (বা মূল প্রোগ্রাম) এর সাথে কিছু ভাগ করে না, আপনি concurrent.futuresএকটি থ্রেড পুলের চারপাশে আপনার কোডটি লিখতে পাঠাগারটি ব্যবহার করতে পারেন :

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    executor.submit(job, argument)
    executor.map(some_function, collection_of_independent_things)
    # ...

এমনকি আপনি এই চাকরিগুলির ফলাফল পেতে এবং সেগুলিকে পরবর্তী চাকরিতে স্থান দিতে পারেন, কার্য সম্পাদনের ক্ষেত্রে বা সমাপ্তির ক্রম ইত্যাদির জন্য অপেক্ষা করতে পারেন; Futureবিশদগুলির জন্য অবজেক্টগুলির বিভাগটি পড়ুন ।

এখন, যদি এটি সক্রিয় হয় যে আপনার প্রোগ্রামটি নিয়মিত 100% সিপিইউ ব্যবহার করে চলেছে এবং আরও থ্রেড যুক্ত করা এটি ধীর করে তোলে তবে আপনি জিআইএল সমস্যা নিয়ে চলেছেন, সুতরাং আপনাকে প্রক্রিয়াগুলিতে স্যুইচ করতে হবে। আপনাকে যা করতে হবে তা হ'ল প্রথম লাইনটি পরিবর্তন করা:

with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:

একমাত্র আসল সতর্কতাই হ'ল আপনার কাজের আর্গুমেন্ট এবং রিটার্ন মানগুলি বাছাইযোগ্য হতে হবে (এবং খুব বেশি সময় বা স্মৃতি নিতে না পারা) ব্যবহারযোগ্য ক্রস প্রক্রিয়া হতে পারে। সাধারণত এটি কোনও সমস্যা নয়, তবে কখনও কখনও এটি হয়।


কিন্তু যদি আপনার কাজগুলি স্বনির্ভর না হয়ে যায়? যদি আপনি এমন কোনও কাজের ক্ষেত্রে আপনার কোডটি ডিজাইন করতে পারেন যা একের পর এক বার্তা পাঠায় তবে এটি এখনও বেশ সহজ। আপনাকে পুলগুলিতে নির্ভর করতে threading.Threadবা multiprocessing.Processতার পরিবর্তে ব্যবহার করতে হতে পারে । এবং আপনাকে স্পষ্টভাবে তৈরি queue.Queueবা multiprocessing.Queueঅবজেক্ট তৈরি করতে হবে । (এখানে প্রচুর অন্যান্য বিকল্প রয়েছে — পাইপ, সকেট, পশুর সাথে ফাইলগুলি,… তবে মুল বক্তব্যটি হ'ল যদি কোনও নির্বাহকের স্বয়ংক্রিয় যাদু অপর্যাপ্ত থাকে তবে আপনাকে ম্যানুয়ালি কিছু করতে হবে ))

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


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

  1. থ্রেডগুলি ডিফল্টরূপে ডেটা ভাগ করে; প্রক্রিয়া না।
  2. (1) এর ফলস্বরূপ, প্রক্রিয়াগুলির মধ্যে ডেটা প্রেরণের জন্য সাধারণত এটি বাছাই করা এবং আন-পিক করা প্রয়োজন। **
  3. (1) এর অন্য ফলাফল হিসাবে, প্রক্রিয়াগুলির মধ্যে সরাসরি ডেটা ভাগ করে নেওয়ার জন্য সাধারণত এটি মান, অ্যারে এবং ctypesপ্রকারের মতো নিম্ন-স্তরের ফর্ম্যাটগুলিতে স্থাপন করা প্রয়োজন ।
  4. প্রক্রিয়াগুলি জিআইএল সাপেক্ষে নয়।
  5. কিছু প্ল্যাটফর্মে (মূলত উইন্ডোজ), প্রক্রিয়াগুলি তৈরি এবং ধ্বংস করতে অনেক বেশি ব্যয়বহুল।
  6. প্রক্রিয়াগুলিতে কিছু অতিরিক্ত বিধিনিষেধ রয়েছে, যার কয়েকটি বিভিন্ন প্ল্যাটফর্মগুলিতে আলাদা। বিশদ জন্য প্রোগ্রামিং গাইডলাইন দেখুন ।
  7. threadingমডিউল বৈশিষ্ট্য কিছু নেই multiprocessingমডিউল। (আপনি multiprocessing.dummyথ্রেডগুলির শীর্ষে বেশিরভাগ অনুপস্থিত এপিআই পেতে ব্যবহার করতে পারেন , বা আপনি concurrent.futuresএটি সম্পর্কে উদ্বিগ্ন না হয়ে উচ্চ স্তরের মডিউলগুলি ব্যবহার করতে পারেন ))

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

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


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

3
@ লুকাক্রোন: আহ, যদি আপনার কোডটি তার বেশিরভাগ সময় বাইরের প্রোগ্রামগুলির জন্য অপেক্ষা করে ব্যয় করে, তবে হ্যাঁ, এটি থ্রেডিংয়ের মাধ্যমে উপকৃত হবে। ভাল যুক্তি. আমি এটি ব্যাখ্যা করতে উত্তর সম্পাদনা করি।
অবতারিত

2
@ লুকাক্রোন: এদিকে, আপনি কোন অংশগুলি বুঝতে পারছেন না? আপনি যে জ্ঞানের স্তরটি দিয়ে শুরু করছেন তা না জেনে একটি ভাল উত্তর লেখা শক্ত ... তবে কিছু প্রতিক্রিয়া সহ, সম্ভবত আমরা এমন কিছু নিয়ে আসতে পারি যা আপনার এবং ভবিষ্যতের পাঠকদের জন্যও সহায়ক।

3
@ লুকাকেরোন আপনার এখানে মাল্টিপ্রসেসিংয়ের জন্য পিইপি পড়া উচিত । এটি সময় এবং বনাম মাল্টিপ্রসেসিংয়ের উদাহরণ দেয়।
mr2ert

1
@ লুকাক্রোন: যদি পদ্ধতিটির বাধ্যবাধকতার সাথে কোনও জটিল অবস্থা না থাকে তবে পিকিং ইস্যুটির সহজতম কাজটি হ'ল একটি বোকা মোড়ক ফাংশন লিখুন যা বস্তুকে উত্পন্ন করে এবং তার পদ্ধতিটি কল করে। এটা যদি না জটিল রাষ্ট্র থাকে, তখন আপনি সম্ভবত এটি picklable করতে হবে (যা প্রশংসনীয় সহজ; pickleডক্স তা ব্যাখ্যা), এবং তারপর খারাপ আপনার মূঢ় মোড়কের হয় def wrapper(obj, *args): return obj.wrapper(*args)
অবতারিত

32

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

আপনি যদি কোনও গণনার সমান্তরাল করতে চান তবে আপনার সম্ভবত মাল্টিথ্রেডিংয়ের প্রয়োজন হবে কারণ আপনি সম্ভবত থ্রেডগুলি একই স্মৃতিতে সহযোগিতা করতে চান।

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


12
এটি জিআইএল সম্পর্কিত কিছু গুরুত্বপূর্ণ তথ্য অনুপস্থিত যা এটি বিভ্রান্তিকর করে তোলে।

1
@ মিঃ2 আর্ট: হ্যাঁ, এটি সংক্ষেপে খুব গুরুত্বপূর্ণ তথ্য। :) তবে এটি তার চেয়ে কিছুটা জটিল, যার কারণেই আমি আলাদা উত্তর লিখেছিলাম।
অবার্নেট

2
আমি ভেবেছিলাম যে আমি মন্তব্য করেছিলাম যে @ বার্নার্ট সঠিক, এবং আমি এখানে জবাব দিতে জিআইএল সম্পর্কে ভুলে গেছি। সুতরাং এই উত্তরটি ভুল, আপনার এটি উড়িয়ে দেওয়া উচিত নয়।
জিউলিও ফ্রাঙ্কো

6
আমি এই উত্তরটিকে অগ্রাহ্য করেছি কারণ পাইথন threadingএবং এর মধ্যে পার্থক্য কী তা এখনও কোনও উত্তর দেয় না multiprocessing
অ্যান্টি হাপালা

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

3

আমি বিশ্বাস করি যে এই লিঙ্কটি আপনার প্রশ্নের উত্তর একটি মার্জিত উপায়ে দেয়।

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


3

পাইথন ডকুমেন্টেশন উদ্ধৃতি

আমি প্রসেস বনাম থ্রেডস এবং জিআইএল সম্পর্কিত পাইথন ডকুমেন্টেশনের উদ্ধৃতিগুলি হাইলাইট করেছি: সিপিথনে গ্লোবাল ইন্টারপ্রেটার লক (জিআইএল) কী?

প্রক্রিয়া বনাম থ্রেড পরীক্ষা-নিরীক্ষা

পার্থক্যটি আরও দৃ concrete়তার সাথে দেখানোর জন্য আমি কিছুটা বেঞ্চমার্কিং করেছি।

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

ফলাফলগুলি ছিল:

এখানে চিত্র বর্ণনা লিখুন

প্লট ডেটা

উপসংহার:

  • সিপিইউ বাউন্ড কাজের জন্য মাল্টিপ্রসেসিং সবসময় দ্রুত হয়, সম্ভবত জিআইএল-এর কারণে

  • আইও আবদ্ধ কাজের জন্য। উভয় ঠিক একই গতি

  • থ্রেডগুলি কেবলমাত্র 8x এর পরিবর্তে প্রায় 4x পর্যন্ত স্কেল করে যেহেতু আমি একটি 8 হাইপারথ্রেড মেশিনে আছি।

    একটি সি পসিক্স সিপিইউ-ভিত্তিক কাজের সাথে বৈসাদৃশ্য করুন যা প্রত্যাশিত 8 এক্স স্পিডআপে পৌঁছেছে: সময়ের (1) আউটপুটে 'রিয়েল', 'ব্যবহারকারী' এবং 'সিজ' কী বোঝায়?

    টোডো: এর কারণ আমি জানি না, পাইথনের অন্যান্য অদক্ষতা অবশ্যই কার্যকর হবে।

পরীক্ষার কোড:

#!/usr/bin/env python3

import multiprocessing
import threading
import time
import sys

def cpu_func(result, niters):
    '''
    A useless CPU bound function.
    '''
    for i in range(niters):
        result = (result * result * i + 2 * result * i * i + 3) % 10000000
    return result

class CpuThread(threading.Thread):
    def __init__(self, niters):
        super().__init__()
        self.niters = niters
        self.result = 1
    def run(self):
        self.result = cpu_func(self.result, self.niters)

class CpuProcess(multiprocessing.Process):
    def __init__(self, niters):
        super().__init__()
        self.niters = niters
        self.result = 1
    def run(self):
        self.result = cpu_func(self.result, self.niters)

class IoThread(threading.Thread):
    def __init__(self, sleep):
        super().__init__()
        self.sleep = sleep
        self.result = self.sleep
    def run(self):
        time.sleep(self.sleep)

class IoProcess(multiprocessing.Process):
    def __init__(self, sleep):
        super().__init__()
        self.sleep = sleep
        self.result = self.sleep
    def run(self):
        time.sleep(self.sleep)

if __name__ == '__main__':
    cpu_n_iters = int(sys.argv[1])
    sleep = 1
    cpu_count = multiprocessing.cpu_count()
    input_params = [
        (CpuThread, cpu_n_iters),
        (CpuProcess, cpu_n_iters),
        (IoThread, sleep),
        (IoProcess, sleep),
    ]
    header = ['nthreads']
    for thread_class, _ in input_params:
        header.append(thread_class.__name__)
    print(' '.join(header))
    for nthreads in range(1, 2 * cpu_count):
        results = [nthreads]
        for thread_class, work_size in input_params:
            start_time = time.time()
            threads = []
            for i in range(nthreads):
                thread = thread_class(work_size)
                threads.append(thread)
                thread.start()
            for i, thread in enumerate(threads):
                thread.join()
            results.append(time.time() - start_time)
        print(' '.join('{:.6e}'.format(result) for result in results))

গিটিহাব আপস্ট্রিম + একই ডিরেক্টরিতে প্লটিং কোড

সিপিইউ সহ একটি লেনোভো থিংকপ্যাড পি 51 ল্যাপটপে উবুন্টু 18.10, পাইথন 3.6.7 এ পরীক্ষিত: ইনটেল কোর আই 7-7820 এইচকিউ সিপিইউ (4 কোর / 8 থ্রেড), র‌্যাম: 2x স্যামসাং এম 471 এ 2 কে 43 বিবি 1-সিআরসি (2x 16 জিবিবি), এসএসডি: স্যামসাং এমজেডভিএলবি 512জেএইচ 000L7 (3,000 এমবি / গুলি)

কোন নির্দিষ্ট সময়ে কোন থ্রেড চলছে তা ভিজ্যুয়ালাইজ করুন

এই পোস্টটি https://rohanvarma.me/GIL/ আমাকে শিখিয়েছে যে যখনই থ্রেডের target=যুক্তিthreading.Thread এবং একইটির জন্য নির্ধারিত হবে আপনি কলব্যাক চালাতে পারবেন multiprocessing.Process

এটি আমাদের প্রতিটি সময় ঠিক কোন থ্রেডে চলে তা দেখতে দেয়। এটি হয়ে গেলে, আমরা এরকম কিছু দেখতে পাই (আমি এই নির্দিষ্ট গ্রাফটি তৈরি করেছি):

            +--------------------------------------+
            + Active threads / processes           +
+-----------+--------------------------------------+
|Thread   1 |********     ************             |
|         2 |        *****            *************|
+-----------+--------------------------------------+
|Process  1 |***  ************** ******  ****      |
|         2 |** **** ****** ** ********* **********|
+-----------+--------------------------------------+
            + Time -->                             +
            +--------------------------------------+

যা এটি দেখায়:

  • থ্রেডগুলি পুরোপুরি জিআইএল দ্বারা সিরিয়ালিত করা হয়
  • প্রক্রিয়া সমান্তরালে চলতে পারে

1

পাইথন ২.6.x এর কিছু পারফরম্যান্স ডেটা এখানে আইও-বাউন্ড দৃশ্যে মাল্টিপ্রসেসিংয়ের ক্ষেত্রে থ্রেডিং আরও পারফরম্যান্ট এই ধারণাকে প্রশ্ন করার জন্য কল করে। এই ফলাফলগুলি 40-প্রসেসরের আইবিএম সিস্টেম x3650 এম 4 বিডি থেকে।

আইও-বাউন্ড প্রসেসিং: প্রসেস পুল থ্রেড পুলের চেয়ে আরও ভাল পারফর্ম করেছে

>>> do_work(50, 300, 'thread','fileio')
do_work function took 455.752 ms

>>> do_work(50, 300, 'process','fileio')
do_work function took 319.279 ms

সিপিইউ-বাউন্ড প্রসেসিং: প্রসেস পুল থ্রেড পুলের চেয়ে আরও ভাল পারফর্ম করেছে

>>> do_work(50, 2000, 'thread','square')
do_work function took 338.309 ms

>>> do_work(50, 2000, 'process','square')
do_work function took 287.488 ms

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

উপরের পরীক্ষাগুলির জন্য ইন্টারেক্টিভ পাইথন কনসোলে ব্যবহৃত কোড

from multiprocessing import Pool
from multiprocessing.pool import ThreadPool
import time
import sys
import os
from glob import glob

text_for_test = str(range(1,100000))

def fileio(i):
 try :
  os.remove(glob('./test/test-*'))
 except : 
  pass
 f=open('./test/test-'+str(i),'a')
 f.write(text_for_test)
 f.close()
 f=open('./test/test-'+str(i),'r')
 text = f.read()
 f.close()


def square(i):
 return i*i

def timing(f):
 def wrap(*args):
  time1 = time.time()
  ret = f(*args)
  time2 = time.time()
  print '%s function took %0.3f ms' % (f.func_name, (time2-time1)*1000.0)
  return ret
 return wrap

result = None

@timing
def do_work(process_count, items, process_type, method) :
 pool = None
 if process_type == 'process' :
  pool = Pool(processes=process_count)
 else :
  pool = ThreadPool(processes=process_count)
 if method == 'square' : 
  multiple_results = [pool.apply_async(square,(a,)) for a in range(1,items)]
  result = [res.get()  for res in multiple_results]
 else :
  multiple_results = [pool.apply_async(fileio,(a,)) for a in range(1,items)]
  result = [res.get()  for res in multiple_results]


do_work(50, 300, 'thread','fileio')
do_work(50, 300, 'process','fileio')

do_work(50, 2000, 'thread','square')
do_work(50, 2000, 'process','square')

আমি তোমার কোড (মুছে ব্যবহার করেছেন উল্লিখিত glob অংশ) এবং পাইথন 2.6.6 সঙ্গে এই আকর্ষণীয় ফলাফল খুঁজে পেয়েছি:>>> do_work(50, 300, 'thread', 'fileio') --> 237.557 ms >>> do_work(50, 300, 'process', 'fileio') --> 323.963 ms >>> do_work(50, 2000, 'thread', 'square') --> 232.082 ms >>> do_work(50, 2000, 'process', 'square') --> 282.785 ms
অ্যালান Garrido

-5

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

fill_count = Semaphore(0) # items produced
empty_count = Semaphore(BUFFER_SIZE) # remaining space
buffer = Buffer()

def producer(fill_count, empty_count, buffer):
    while True:
        item = produceItem()
        empty_count.down();
        buffer.push(item)
        fill_count.up()

def consumer(fill_count, empty_count, buffer):
    while True:
        fill_count.down()
        item = buffer.pop()
        empty_count.up()
        consume_item(item)

আপনি থেকে সিঙ্ক্রোনাইজেশন আদিমগুলিতে আরও পড়তে পারেন:

 http://linux.die.net/man/7/sem_overview
 http://docs.python.org/2/library/threading.html

সিউডোকোড উপরে রয়েছে। আমি মনে করি আপনার আরও রেফারেন্স পেতে প্রযোজক-ভোক্তা-সমস্যাটি অনুসন্ধান করা উচিত।


দুঃখিত ইনোসাম, তবে এটি আমার কাছে সি ++ বলে মনে হচ্ছে? লিঙ্কগুলির জন্য ধন্যবাদ :)
lucacerone

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

2
এটি সি ++ নয়; এটি সিউডোকোড (অথবা এটি একটি সি-এর মতো বাক্য গঠন সহ বেশিরভাগ গতিশীল টাইপযুক্ত ভাষার জন্য কোড That এটি বলা হচ্ছে, আমি পাইথন ব্যবহারকারীদের পড়ানোর জন্য পাইথনের মতো সিউডোকোড লেখার পক্ষে আরও দরকারী বলে মনে করি ((বিশেষত পাইথনের মতো স্যুইচোকোড প্রায়শই চালানো যায় এমন কোড হতে দেখা যায় বা এটির কমপক্ষে, এটি সি-এর মতো সিউডোকোডের পক্ষে খুব কমই সত্য ...)
অবার্নেট

আমি এটিকে পাইথনের মতো সিউডোকোড (আবার ওও ব্যবহার করে এবং বিশ্বব্যাপী বস্তু ব্যবহারের পরিবর্তে প্যারামিটারগুলিও পাস করেছি) হিসাবে আবার লিখেছি; যদি আপনি মনে করেন যে বিষয়গুলি কম স্পষ্ট করে তোলে তবে নির্দ্বিধায় উদ্বিগ্ন হন।
অবতারিত

এছাড়াও, এটি লক্ষণীয় যে পাইথন স্টাডলিবের মধ্যে একটি সিঙ্ক্রোনাইজ করা সারি রয়েছে যা এই সমস্ত বিবরণকে আবৃত করে এবং এর থ্রেড এবং প্রক্রিয়া পুলের API গুলি আরও কিছু বিমূর্ত জিনিসকে আরও দেয়। এটি কীভাবে সিঙ্ক্রোনাইজ করা কাতারগুলি কভারগুলির নীচে কাজ করে তা স্পষ্টতই মূল্যবান তবে আপনাকে নিজেরাই খুব কমই লিখতে হবে।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.