অজগর মাল্টিথ্রেডিং সমস্ত থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করুন


119

এটি অনুরূপ প্রসঙ্গে জিজ্ঞাসা করা হতে পারে তবে আমি প্রায় 20 মিনিটের সন্ধানের পরে কোনও উত্তর খুঁজে পাইনি, তাই আমি জিজ্ঞাসা করব।

আমি পাইথন স্ক্রিপ্ট লিখেছি (বলতে দিন: স্ক্রিপ্টএ.পি) এবং স্ক্রিপ্ট (স্ক্রিপ্টবি.পি বলতে দিন)

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

import subprocess

#setup
do_setup()

#run scriptA
subprocess.call(scriptA + argumentsA)
subprocess.call(scriptA + argumentsB)
subprocess.call(scriptA + argumentsC)

#finish
do_finish()

আমি subprocess.call()একই সাথে সমস্ত চালাতে চাই এবং তারপরে সেগুলি সম্পন্ন হওয়া পর্যন্ত অপেক্ষা করুন, আমি এটি কীভাবে করব?

আমি এখানে উদাহরণের মতো থ্রেডিং ব্যবহার করার চেষ্টা করেছি :

from threading import Thread
import subprocess

def call_script(args)
    subprocess.call(args)

#run scriptA   
t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))
t1.start()
t2.start()
t3.start()

তবে আমি এটি সঠিক বলে মনে করি না।

আমি কীভাবে জানতে পারি যে আমার কাছে যাওয়ার আগে তারা সব শেষ করে ফেলেছে do_finish()?

উত্তর:


150

স্ক্রিপ্টের শেষে আপনাকে অবজেক্টের যোগ পদ্ধতি ব্যবহার করতে হবে Thread

t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()

এভাবে মূল থ্রেড পর্যন্ত অপেক্ষা করবে t1, t2এবং t3মৃত্যুদন্ড শেষ।


5
হুঁ - কোন কিছু বুঝতে সমস্যা হচ্ছে, এই প্রথম চালানো টি 1 এড়াবে না, তার সমাপ্তি অবধি অপেক্ষা করুন, তারপরে টি 2 এ যান ... ইত্যাদি? কীভাবে এটি একবারে ঘটতে পারে? আমি দেখতে পাচ্ছি না কীভাবে এটি একই সাথে তাদের চালাবেন?
ইনবার রোজ

25
joinথ্রেডের কার্যকারিতা শেষ না হওয়া অবধি ব্লকে কল । যাইহোক আপনাকে সমস্ত থ্রেডের জন্য অপেক্ষা করতে হবে। যদি t1শেষ প্রথমে আপনার অপেক্ষায় শুরু হবে t2(ইতিমধ্যে সমাপ্ত যা পারে যাবে এবং আপনি অবিলম্বে জন্য অপেক্ষা করতে এগিয়ে যেতে হবে t3)। t1কার্যকর করতে যদি সবচেয়ে বেশি সময় নেয় তবে আপনি যখন উভয় থেকে ফিরে আসেন t1এবং t2অবরুদ্ধ না করে অবিলম্বে ফিরে আসবেন।
মাকসিম স্কুরিডজিন

1
আপনি আমার প্রশ্নটি বুঝতে পারবেন না - যদি আমি আমার কোডটিতে উপরের কোডটি অনুলিপি করি - তবে এটি কার্যকর হবে? নাকি আমি কিছু মিস করছি?
ইনবার রোজ

2
ঠিক আছে আমি দেখছি. এখন আমি বুঝতে পেরেছি, এটি সম্পর্কে কিছুটা বিভ্রান্ত হয়েছিল তবে আমি মনে করি আমি বুঝতে পেরেছি, এক joinপ্রকারের বর্তমান প্রক্রিয়াটি থ্রেডের সাথে সংযুক্ত করে এটি সম্পন্ন হওয়া পর্যন্ত অপেক্ষা করে, এবং যদি টি 2 টি 1 এর আগে সমাপ্ত হয় তখন টি 1 সম্পন্ন হওয়ার পরে এটি টি 2 হয়ে যাওয়ার জন্য পরীক্ষা করবে দেখুন এটি হ'ল, এবং তারপরে t3..etc..etc .. পরীক্ষা করুন এবং তারপরে সমস্ত কাজ শেষ হলেই এটি চালিয়ে যাবে। অসাধারণ.
ইনবার রোজ

3
বলুন টি 1 সবচেয়ে দীর্ঘ সময় নেয় তবে টি 2 এর ব্যতিক্রম রয়েছে। তাহলে কি হবে? আপনি কি সেই ব্যতিক্রমটি ধরতে পারবেন বা পরীক্ষা করতে পারেন টি 2 ঠিক আছে কিনা?
সিপরিয়ান টমোইগা

174

থ্রেডগুলিকে একটি তালিকায় রাখুন এবং তারপরে যোগদানের পদ্ধতিটি ব্যবহার করুন

 threads = []

 t = Thread(...)
 threads.append(t)

 ...repeat as often as necessary...

 # Start all threads
 for x in threads:
     x.start()

 # Wait for all of them to finish
 for x in threads:
     x.join()

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

2
"ফ্যাক্টরি প্যাটার্ন" এমন কিছু নয় যা আমি একটি বাক্যে ব্যাখ্যা করতে পারি। এটির জন্য গুগল এবং stackoverflow.com অনুসন্ধান করুন .com অনেক উদাহরণ এবং ব্যাখ্যা আছে। সংক্ষেপে: আপনি কোড লিখেছেন যা আপনার জন্য জটিল কিছু তৈরি করে। একটি বাস্তব কারখানার মতো: আপনি একটি অর্ডার দিন এবং একটি সমাপ্ত পণ্য ফিরে পাবেন।
অ্যারন দিগুল্লা

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

1
অ্যারোন ডিগুল আমি এটি বুঝতে পেরেছি I আমার অর্থ হ'ল আমি for x in threads: x.join()তালিকা বোধগম্যতা ব্যবহার না করে কেবল একটি কাজ করব
আলেকজান্দ্রু কুকু

1
@IoanAlexandruCucu: আমি এখনও ভাবছি করছি আছে যদি একটি আরো ভালো পঠনযোগ্য ও দক্ষ সমাধান: stackoverflow.com/questions/21428602/...
হারুন Digulla

29

Python3 সালে পাইথন 3.2 যেহেতু, একই ফলাফল পৌঁছানোর একটি নতুন পদ্ধতির যে আমি ব্যক্তিগতভাবে / ঐতিহ্যগত থ্রেড সৃষ্টি করতে পছন্দ শুরু করুন / যোগদানের, প্যাকেজ concurrent.futures: https://docs.python.org/3/library/concurrent.futures .html

ThreadPoolExecutorকোড ব্যবহার করা হবে:

from concurrent.futures.thread import ThreadPoolExecutor
import time

def call_script(ordinal, arg):
    print('Thread', ordinal, 'argument:', arg)
    time.sleep(2)
    print('Thread', ordinal, 'Finished')

args = ['argumentsA', 'argumentsB', 'argumentsC']

with ThreadPoolExecutor(max_workers=2) as executor:
    ordinal = 1
    for arg in args:
        executor.submit(call_script, ordinal, arg)
        ordinal += 1
print('All tasks has been finished')

পূর্ববর্তী কোডটির আউটপুট এমন কিছু:

Thread 1 argument: argumentsA
Thread 2 argument: argumentsB
Thread 1 Finished
Thread 2 Finished
Thread 3 argument: argumentsC
Thread 3 Finished
All tasks has been finished

সুবিধাগুলির মধ্যে একটি হ'ল আপনি সর্বাধিক সমবর্তী কর্মীদের সেটিং থ্রুপুটটি নিয়ন্ত্রণ করতে পারেন।


থ্রেডপুলের সমস্ত থ্রেড শেষ হয়ে গেলে আপনি কীভাবে বলতে পারেন?
প্রাইম বাই ডিজাইন

1
উদাহরণস্বরূপ আপনি দেখতে পাচ্ছেন, withসমস্ত টাস্ক শেষ হয়ে গেলে বিবৃতি কার্যকর করার পরে কোডটি কার্যকর করা হয়।
রবার্তো

এটি কাজ করে না থ্রেডগুলিতে সত্যিই দীর্ঘ কিছু করার চেষ্টা করুন। আপনার মুদ্রণ বিবৃতিটি থ্রেড শেষ হওয়ার আগেই কার্যকর করা হবে
প্রণালি

@ প্রণালি, এই কোডটি কাজ করে, আউটপুট লাইন যুক্ত করতে আমি কোড আপডেট করেছি। সমস্ত থ্রেড শেষ হওয়ার আগে আপনি "সমস্ত টাস্ক ..." দেখতে পারবেন না, withএই ক্ষেত্রে বিবৃতিটি ডিজাইন অনুসারে কাজ করে। যাইহোক, আপনি সর্বদা এসও তে একটি নতুন প্রশ্ন খুলতে পারেন এবং আপনার কোড পোস্ট করতে পারেন যাতে আপনার ক্ষেত্রে কী ঘটছে তা খুঁজে পেতে আমরা আপনাকে সহায়তা করতে পারি।
রবার্তো

@ প্রাইমবাই ডিজাইন আপনি concurrent.futures.waitফাংশনটি ব্যবহার করতে পারেন , আপনি এখানে একটি বাস্তব উদাহরণ দেখতে পাবেন অফিসিয়াল ডক্স: ডকস.পিথন.আর
আলেকজান্ডার ফোর্টিন

28

আমি ইনপুট তালিকার উপর ভিত্তি করে তালিকা বোঝার ব্যবহার পছন্দ করি:

inputs = [scriptA + argumentsA, scriptA + argumentsB, ...]
threads = [Thread(target=call_script, args=(i)) for i in inputs]
[t.start() for t in threads]
[t.join() for t in threads]

চেক করা উত্তরগুলি ভাল ব্যাখ্যা করে তবে এইটি সংক্ষিপ্ত এবং কুৎসিত পুনরাবৃত্তিগুলির প্রয়োজন নেই। শুধু একটি সুন্দর উত্তর। :)
টিলেব

পার্শ্ব প্রতিক্রিয়াগুলির জন্য তালিকা বোধগম্যতা সাধারণত হ্রাস করা হয় *। তবে এই ব্যবহারের ক্ষেত্রে এটি একটি ভাল ধারণা বলে মনে হয়। * Stackoverflow.com/questions/5753597/...
বিনায়ক Kaniyarakkal

3
@ বিনায়াকণিয়র্ককাল for t in threads:t.start()ভাল না?
স্মার্টমনোজ 23'18

5

আপনার ক্লাসের নীচের মতো কিছু থাকতে পারে যা থেকে আপনি 'এন' সংখ্যার ফাংশন যুক্ত করতে পারেন বা কনসোল_স্ক্রিপ্টগুলি সমান্তরাল আবেগের সাথে নির্বাহ করতে চান এবং সম্পাদন শুরু করতে পারেন এবং সমস্ত কাজ শেষ হওয়ার জন্য অপেক্ষা করতে পারেন ..

from multiprocessing import Process

class ProcessParallel(object):
    """
    To Process the  functions parallely

    """    
    def __init__(self, *jobs):
        """
        """
        self.jobs = jobs
        self.processes = []

    def fork_processes(self):
        """
        Creates the process objects for given function deligates
        """
        for job in self.jobs:
            proc  = Process(target=job)
            self.processes.append(proc)

    def start_all(self):
        """
        Starts the functions process all together.
        """
        for proc in self.processes:
            proc.start()

    def join_all(self):
        """
        Waits untill all the functions executed.
        """
        for proc in self.processes:
            proc.join()


def two_sum(a=2, b=2):
    return a + b

def multiply(a=2, b=2):
    return a * b


#How to run:
if __name__ == '__main__':
    #note: two_sum, multiply can be replace with any python console scripts which
    #you wanted to run parallel..
    procs =  ProcessParallel(two_sum, multiply)
    #Add all the process in list
    procs.fork_processes()
    #starts  process execution 
    procs.start_all()
    #wait until all the process got executed
    procs.join_all()

এটি মাল্টিপ্রসেসিং। ডকস.পিথন.আর. / ৩
রুস্তম এ।

3

থেকে threading মডিউল ডকুমেন্টেশন

একটি "মূল থ্রেড" অবজেক্ট রয়েছে; এটি পাইথন প্রোগ্রামের নিয়ন্ত্রণের প্রাথমিক থ্রেডের সাথে মিলে যায়। এটি কোনও ডেমন থ্রেড নয়।

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

সুতরাং, যখন আপনি তৈরি থ্রেডগুলির একটি তালিকা রাখতে আগ্রহী নন তখন এই দুটি কেস ধরতে:

import threading as thrd


def alter_data(data, index):
    data[index] *= 2


data = [0, 2, 6, 20]

for i, value in enumerate(data):
    thrd.Thread(target=alter_data, args=[data, i]).start()

for thread in thrd.enumerate():
    if thread.daemon:
        continue
    try:
        thread.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err.args[0]:
            # catchs main thread
            continue
        else:
            raise

সেজন্য হেরোদ:

>>> print(data)
[0, 4, 12, 40]

2

হতে পারে, কিছু

for t in threading.enumerate():
    if t.daemon:
        t.join()

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

1

লুপের জন্য তৈরি হওয়া সমস্ত থ্রেডের জন্য অপেক্ষা করার দরকার পড়ে আমি একই সমস্যার মুখোমুখি হয়েছি। আমি নীচের কোডটির কিছু অংশ চেষ্টা করেছিলাম t এটি সঠিক সমাধান নাও হতে পারে তবে আমি ভেবেছিলাম এটি একটি সহজ সমাধান হবে পরীক্ষা করতে:

for t in threading.enumerate():
    try:
        t.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err:
            continue
        else:
            raise
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.