পাইথনের থ্রেড থেকে রিটার্নের মান কীভাবে পাবেন?


342

ফাংশন fooআয় নিচে একটি স্ট্রিং 'foo''foo'থ্রেডের লক্ষ্য থেকে ফেরত দেওয়া মান আমি কীভাবে পেতে পারি ?

from threading import Thread

def foo(bar):
    print('hello {}'.format(bar))
    return 'foo'

thread = Thread(target=foo, args=('world!',))
thread.start()
return_value = thread.join()

উপরে দেখানো "এটি করার একটি সুস্পষ্ট উপায়", কাজ করে না: thread.join()ফিরে এসেছে None

উত্তর:


37

পাইথন ৩.২+ এ, স্টাডলিব concurrent.futuresমডিউল একটি উচ্চ স্তরের এপিআই সরবরাহ করে threading, যার সাথে কোনও কর্মী থ্রেড থেকে মূল থ্রেডে ফিরে আসার মান বা ব্যতিক্রমগুলি অন্তর্ভুক্ত থাকে:

import concurrent.futures

def foo(bar):
    print('hello {}'.format(bar))
    return 'foo'

with concurrent.futures.ThreadPoolExecutor() as executor:
    future = executor.submit(foo, 'world!')
    return_value = future.result()
    print(return_value)

যারা ভাবছেন তাদের জন্য থ্রেডগুলির একটি তালিকা দিয়ে এটি করা যেতে পারে। futures = [executor.submit(foo, param) for param in param_list]অর্ডার বজায় রাখা হবে, এবং প্রস্থানটি withফলাফল সংগ্রহের অনুমতি দেবে। [f.result() for f in futures]
jayreed1

273

FWIW, ক্লাসটি multiprocessingব্যবহার করে মডিউলটির জন্য একটি দুর্দান্ত ইন্টারফেস রয়েছে nice Poolএবং যদি আপনি প্রক্রিয়াগুলির পরিবর্তে থ্রেডগুলির সাথে লেগে থাকতে চান তবে আপনি multiprocessing.pool.ThreadPoolক্লাসটি ড্রপ-ইন প্রতিস্থাপন হিসাবে ব্যবহার করতে পারেন ।

def foo(bar, baz):
  print 'hello {0}'.format(bar)
  return 'foo' + baz

from multiprocessing.pool import ThreadPool
pool = ThreadPool(processes=1)

async_result = pool.apply_async(foo, ('world', 'foo')) # tuple of args for foo

# do some other stuff in the main process

return_val = async_result.get()  # get the return value from your function.

50
@ জ্যাকবিসিঞ্জার আমার বক্তব্যটি হ'ল, আমি উত্তর খুঁজছিলাম, থ্রেড থেকে কীভাবে প্রতিক্রিয়া পাওয়া যায়, এখানে এসেছি এবং গৃহীত উত্তর প্রশ্নের প্রশ্নের উত্তর দেয় না। আমি থ্রেড এবং প্রক্রিয়াগুলি পৃথক করি। আমি গ্লোবাল ইন্টারপ্রেটার লক সম্পর্কে জানি তবে আমি আই / ও বাউন্ড সমস্যা নিয়ে কাজ করছি সুতরাং থ্রেডস ঠিক আছে, আমার প্রক্রিয়াগুলির দরকার নেই। অন্যান্য উত্তর এখানে ভাল উত্তর উত্তর বর্ণিত।
ওমিক্রন

7
@ ওমিক্রন তবে পাইথনের থ্রেডগুলি কোনও প্রতিক্রিয়া ফেরায় না যদি না আপনি এই সাবক্লাস ব্যবহার করেন যা এই কার্যকারিতা সক্ষম করে। সম্ভাব্য সাবক্লাসগুলির মধ্যে, থ্রেডপুলগুলি দুর্দান্ত পছন্দ (থ্রেডগুলির # টি নির্বাচন করুন, মানচিত্র ব্যবহার করুন / ডাব্লু / সিঙ্ক / অ্যাসিঙ্ক প্রয়োগ করুন)। আমদানি করা সত্ত্বেও multiprocess, তাদের প্রক্রিয়াগুলির সাথে কোনও সম্পর্ক নেই।
জ্যাক বিসিঞ্জার

4
@ জ্যাকবিসিঞ্জার ওহ, আমি অন্ধ। আমার অপ্রয়োজনীয় মন্তব্যের জন্য দুঃখিত। তুমি ঠিক. আমি কেবল ধরে নিয়েছি যে মাল্টিপ্রসেসিং = প্রক্রিয়াগুলি।
ওমিক্রন

12
processes=1আপনার আরও থ্রেড থাকলে একের বেশি সেট করতে ভুলবেন না !
ইমান

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

242

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

def foo(bar, result, index):
    print 'hello {0}'.format(bar)
    result[index] = "foo"

from threading import Thread

threads = [None] * 10
results = [None] * 10

for i in range(len(threads)):
    threads[i] = Thread(target=foo, args=('world!', results, i))
    threads[i].start()

# do some other stuff

for i in range(len(threads)):
    threads[i].join()

print " ".join(results)  # what sound does a metasyntactic locomotive make?

যদি আপনি সত্যিই join()কথিত ফাংশনের রিটার্ন মানটি ফিরিয়ে দিতে চান তবে আপনি Threadনীচের মতো একটি সাবক্লাস দিয়ে এটি করতে পারেন :

from threading import Thread

def foo(bar):
    print 'hello {0}'.format(bar)
    return "foo"

class ThreadWithReturnValue(Thread):
    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs={}, Verbose=None):
        Thread.__init__(self, group, target, name, args, kwargs, Verbose)
        self._return = None
    def run(self):
        if self._Thread__target is not None:
            self._return = self._Thread__target(*self._Thread__args,
                                                **self._Thread__kwargs)
    def join(self):
        Thread.join(self)
        return self._return

twrv = ThreadWithReturnValue(target=foo, args=('world!',))

twrv.start()
print twrv.join()   # prints foo

কিছু নাম ম্যাংলিংয়ের কারণে এটি কিছুটা লোমশ হয়ে ওঠে এবং এটি "ব্যক্তিগত" ডেটা স্ট্রাকচারগুলি অ্যাক্সেস করে যা Threadপ্রয়োগের জন্য নির্দিষ্ট ... তবে এটি কার্যকর হয়।

পাইথন 3 এর জন্য

class ThreadWithReturnValue(Thread):
    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs={}, Verbose=None):
        Thread.__init__(self, group, target, name, args, kwargs)
        self._return = None
    def run(self):
        print(type(self._target))
        if self._target is not None:
            self._return = self._target(*self._args,
                                                **self._kwargs)
    def join(self, *args):
        Thread.join(self, *args)
        return self._return

37
শান্ত, উদাহরণের জন্য ধন্যবাদ! আমি আশ্চর্য হয়েছি কেন প্রথম স্থানে রিটার্ন মান হ্যান্ডল করে থ্রেড প্রয়োগ করা হয়নি, এটি সমর্থন করার মতো একটি সুস্পষ্ট যথেষ্ট জিনিস বলে মনে হয়।
wim

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

10
দুর্দান্ত ট্রেনের রসিকতা।
meawoppl

7
পাইথন 3 এ এটি ফিরে আসে TypeError: __init__() takes from 1 to 6 positional arguments but 7 were given। এটা ঠিক করার কোন উপায়?
গাইসফট

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

84

জ্যাকের উত্তরটি ভাল, তবে আপনি যদি কোনও থ্রেডপুল ব্যবহার করতে না চান (আপনার কয়টি থ্রেডের প্রয়োজন হবে তা আপনি জানেন না তবে প্রয়োজনীয় হিসাবে সেগুলি তৈরি করুন) তবে থ্রেডগুলির মধ্যে তথ্য প্রেরণের একটি ভাল উপায় হ'ল বিল্ট-ইন ক্যু.কিউ ক্লাস, এটি থ্রেড সুরক্ষা সরবরাহ করে।

থ্রেডপুলের অনুরূপ ফ্যাশনে এটিকে অভিনয় করার জন্য আমি নীচের সাজসজ্জা তৈরি করেছি:

def threaded(f, daemon=False):
    import Queue

    def wrapped_f(q, *args, **kwargs):
        '''this function calls the decorated function and puts the 
        result in a queue'''
        ret = f(*args, **kwargs)
        q.put(ret)

    def wrap(*args, **kwargs):
        '''this is the function returned from the decorator. It fires off
        wrapped_f in a new thread and returns the thread object with
        the result queue attached'''

        q = Queue.Queue()

        t = threading.Thread(target=wrapped_f, args=(q,)+args, kwargs=kwargs)
        t.daemon = daemon
        t.start()
        t.result_queue = q        
        return t

    return wrap

তারপরে আপনি এটিকে কেবল এটি ব্যবহার করুন:

@threaded
def long_task(x):
    import time
    x = x + 5
    time.sleep(5)
    return x

# does not block, returns Thread object
y = long_task(10)
print y

# this blocks, waiting for the result
result = y.result_queue.get()
print result

সজ্জিত ফাংশনটি প্রতিবার যখন নতুন ড্রেড তৈরি করে তখন এটি তৈরি করে এবং এমন কোনও থ্রেড অবজেক্ট দেয় যা ফলটি গ্রহণ করবে the

হালনাগাদ

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

পাইথন ৩.২ concurrent.futuresমডিউলে যুক্ত হয়েছে যা সমান্তরাল কাজের জন্য একটি উচ্চ-স্তরের ইন্টারফেস সরবরাহ করে। এটি সরবরাহ করে ThreadPoolExecutorএবং ProcessPoolExecutor, যাতে আপনি একই এপিআই সহ একটি থ্রেড বা প্রক্রিয়া পুল ব্যবহার করতে পারেন।

এই এপিআইর একটি সুবিধা হ'ল কোনও কাজকে Executorকোনও Futureবস্তুর কাছে জমা দেওয়া , যা আপনার জমা দেওয়া কলের ফেরতের মূল্যের সাথে সম্পূর্ণ হবে।

এটি কোনও queueঅবজেক্টকে সংযুক্তিযুক্ত করে তোলে , যা সাজসজ্জারকে বেশ কিছুটা সহজ করে তোলে :

_DEFAULT_POOL = ThreadPoolExecutor()

def threadpool(f, executor=None):
    @wraps(f)
    def wrap(*args, **kwargs):
        return (executor or _DEFAULT_POOL).submit(f, *args, **kwargs)

    return wrap

যদি কোনওটি পাস না করা হয় তবে এটি একটি ডিফল্ট মডিউল থ্রেডপুল এক্সিকিউটার ব্যবহার করবে ।

ব্যবহারের আগের মতো:

@threadpool
def long_task(x):
    import time
    x = x + 5
    time.sleep(5)
    return x

# does not block, returns Future object
y = long_task(10)
print y

# this blocks, waiting for the result
result = y.result()
print result

আপনি পাইথন 3.4+, এই পদ্ধতি (ও ভবিষ্যত সাধারণ বস্তু) ব্যবহার করে এক সত্যিই চমৎকার বৈশিষ্ট্য ব্যবহার করেন, তাহলে যে ফিরে ভবিষ্যৎ একটি সেটিকে ঘুরিয়ে আবৃত করা যেতে পারে asyncio.Futureসঙ্গে asyncio.wrap_future। এটি কর্টাইনগুলির সাথে এটি সহজেই কাজ করে:

result = await asyncio.wrap_future(long_task(10))

যদি আপনার অন্তর্নিহিত concurrent.Futureঅবজেক্টে অ্যাক্সেসের প্রয়োজন না হয় , আপনি ডেকরেটারের মধ্যে মোড়ানো অন্তর্ভুক্ত করতে পারেন:

_DEFAULT_POOL = ThreadPoolExecutor()

def threadpool(f, executor=None):
    @wraps(f)
    def wrap(*args, **kwargs):
        return asyncio.wrap_future((executor or _DEFAULT_POOL).submit(f, *args, **kwargs))

    return wrap

তারপরে, ইভেন্ট লুপের থ্রেডটি বন্ধ করার জন্য যখনই আপনাকে সিপিইউ নিবিড় বা ব্লকিং কোডটি চাপতে হবে, আপনি এটিকে সজ্জিত ফাংশনে রাখতে পারেন:

@threadpool
def some_long_calculation():
    ...

# this will suspend while the function is executed on a threadpool
result = await some_long_calculation()

আমি এটি কাজ করতে পারে বলে মনে হয় না; আমি AttributeError: 'module' object has no attribute 'Lock'লাইনটি থেকে প্রকাশিত হচ্ছে বলে মনে হচ্ছে একটি ত্রুটি পেয়েছি y = long_task(10)... চিন্তাভাবনা?
স্যাডমিকোওয়েভ

1
কোডটি স্পষ্টভাবে লক ব্যবহার করে না, সুতরাং সমস্যাটি আপনার কোডের অন্য কোনও জায়গায় হতে পারে। আপনি এটি সম্পর্কে একটি নতুন এসও প্রশ্ন পোস্ট করতে চাইতে পারেন
bj0

রেজাল্ট_কিউ একটি উদাহরণ বৈশিষ্ট্য কেন? এটি আরও ভাল কি যদি এটি একটি শ্রেণি বৈশিষ্ট্য হত যাতে ব্যবহারকারীরা @ থ্রেডড ব্যবহার করার সময় ফলাফল_ক্যুই কল করতে জানতে না পারে যা স্পষ্ট এবং অস্পষ্ট নয়?
ননবোট

@ t88, আপনি কী বোঝাতে চাইছেন তা নিশ্চিত নয়, আপনাকে ফলাফলটি অ্যাক্সেস করার কিছু উপায় প্রয়োজন যার অর্থ আপনার কী কল করতে হবে তা জানতে হবে। আপনি যদি এটি অন্য কিছু হতে চান তবে আপনি থ্রেড সাবক্লাস করতে পারেন এবং যা চান তা করতে পারেন (এটি একটি সহজ সমাধান ছিল)। থ্রেডের সাথে
কিউটি

1
ইহা অসাধারণ! আপনাকে অনেক ধন্যবাদ.
গণেশ কাঠিরসান

53

আর একটি সমাধান যা আপনার বিদ্যমান কোড পরিবর্তন করার প্রয়োজন নেই:

import Queue
from threading import Thread

def foo(bar):
    print 'hello {0}'.format(bar)
    return 'foo'

que = Queue.Queue()

t = Thread(target=lambda q, arg1: q.put(foo(arg1)), args=(que, 'world!'))
t.start()
t.join()
result = que.get()
print result

এটি সহজেই একাধিক-থ্রেড পরিবেশে সমন্বয় করা যেতে পারে:

import Queue
from threading import Thread

def foo(bar):
    print 'hello {0}'.format(bar)
    return 'foo'

que = Queue.Queue()
threads_list = list()

t = Thread(target=lambda q, arg1: q.put(foo(arg1)), args=(que, 'world!'))
t.start()
threads_list.append(t)

# Add more threads here
...
threads_list.append(t2)
...
threads_list.append(t3)
...

# Join all the threads
for t in threads_list:
    t.join()

# Check thread's return value
while not que.empty():
    result = que.get()
    print result

t = থ্রেড (টার্গেট = ল্যাম্বডা কিউ, আরগ 1: কিউ.পুট (ফু (আরজি 1)), আরগস = (কুই, 'ওয়ার্ল্ড!')) এখানে কি কি.পুট করছে, কিউ.কিউ (কি) করে
বিজয় শঙ্কর

6
আপনার শহরে আপনার একটি মূর্তি থাকা উচিত, আপনাকে ধন্যবাদ!
অনিলল

3
@ অনিলল - আপনাকে অনেক ধন্যবাদ আপনার মন্তব্যটি আমি ঠিক এই কারণেই করছি :)
অ্যারিক

4
পাইথন 3 এর জন্য, এটিকে পরিবর্তন করতে হবে from queue import Queue
জিনো মেম্পিন

1
এটি মূলত থ্রেডে ফিরে যাওয়ার মানকে অনুমতি দেওয়ার জন্য সর্বনিম্ন বিঘ্নজনক পদ্ধতি (নাটকীয়ভাবে মূল কোড ভিত্তিক পুনর্গঠন করার প্রয়োজন নেই) বলে মনে হচ্ছে।
ফানচেন বাও

24

প্যারিস / কিন্ডলের উত্তর join / returnউত্তর পাইথন 3 এ পোর্ট করা হয়েছে:

from threading import Thread

def foo(bar):
    print('hello {0}'.format(bar))
    return "foo"

class ThreadWithReturnValue(Thread):
    def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
        Thread.__init__(self, group, target, name, args, kwargs, daemon=daemon)

        self._return = None

    def run(self):
        if self._target is not None:
            self._return = self._target(*self._args, **self._kwargs)

    def join(self):
        Thread.join(self)
        return self._return


twrv = ThreadWithReturnValue(target=foo, args=('world!',))

twrv.start()
print(twrv.join())   # prints foo

দ্রষ্টব্য, Threadক্লাসটি পাইথন 3 এ আলাদাভাবে প্রয়োগ করা হয়েছে।


1
যোগদানের জন্য একটি সময়সীমা প্যারামিটার লাগে যা বরাবর পাস করা উচিত
সিজেড

22

আমি কিন্ডেলের উত্তরটি চুরি করেছি এবং এটি কিছুটা পরিষ্কার করেছি।

সময়সীমাটি পরিচালনা করার জন্য মূল অংশটি * আরগস এবং ** কাওয়ার্গগুলিতে যোগ দিচ্ছে () যোগদানের জন্য

class threadWithReturn(Thread):
    def __init__(self, *args, **kwargs):
        super(threadWithReturn, self).__init__(*args, **kwargs)

        self._return = None

    def run(self):
        if self._Thread__target is not None:
            self._return = self._Thread__target(*self._Thread__args, **self._Thread__kwargs)

    def join(self, *args, **kwargs):
        super(threadWithReturn, self).join(*args, **kwargs)

        return self._return

নীচে উত্তর আপডেট করুন

এটি আমার সর্বাধিক জনপ্রিয় উর্ধ্বমুখী উত্তর, তাই আমি কোডটি আপডেট করার সিদ্ধান্ত নিয়েছি যা পাই 2 এবং পাই 3 উভয়ই চলবে।

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

থ্রেডউইথের্টেন ক্লাস যা পাই 2 এবং পাই 3 এর সাথে কাজ করে:

import sys
from threading import Thread
from builtins import super    # https://stackoverflow.com/a/30159479

if sys.version_info >= (3, 0):
    _thread_target_key = '_target'
    _thread_args_key = '_args'
    _thread_kwargs_key = '_kwargs'
else:
    _thread_target_key = '_Thread__target'
    _thread_args_key = '_Thread__args'
    _thread_kwargs_key = '_Thread__kwargs'

class ThreadWithReturn(Thread):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._return = None

    def run(self):
        target = getattr(self, _thread_target_key)
        if not target is None:
            self._return = target(
                *getattr(self, _thread_args_key),
                **getattr(self, _thread_kwargs_key)
            )

    def join(self, *args, **kwargs):
        super().join(*args, **kwargs)
        return self._return

কিছু নমুনা পরীক্ষা নীচে দেখানো হয়েছে:

import time, random

# TEST TARGET FUNCTION
def giveMe(arg, seconds=None):
    if not seconds is None:
        time.sleep(seconds)
    return arg

# TEST 1
my_thread = ThreadWithReturn(target=giveMe, args=('stringy',))
my_thread.start()
returned = my_thread.join()
# (returned == 'stringy')

# TEST 2
my_thread = ThreadWithReturn(target=giveMe, args=(None,))
my_thread.start()
returned = my_thread.join()
# (returned is None)

# TEST 3
my_thread = ThreadWithReturn(target=giveMe, args=('stringy',), kwargs={'seconds': 5})
my_thread.start()
returned = my_thread.join(timeout=2)
# (returned is None) # because join() timed out before giveMe() finished

# TEST 4
my_thread = ThreadWithReturn(target=giveMe, args=(None,), kwargs={'seconds': 5})
my_thread.start()
returned = my_thread.join(timeout=random.randint(1, 10))

আমরা সম্ভবত যে টেস্ট 4 এর মুখোমুখি হতে পারি সেই কোণার কেসটি সনাক্ত করতে পারি?

সমস্যাটি হ'ল আমরা আশা করি যে মাই () কে কেউ ফিরিয়ে দেবে না (টেস্ট ২ দেখুন), তবে আমরাও আশা করি জয়েন () এর সময় শেষ হলে কোনটিই ফিরে আসবে না।

returned is None এর অর্থ হয়:

(1) এটিই গিমেএম () ফিরে এসেছে, বা

(2) যোগদান () সময়সীমা শেষ

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

নীচে এই কোণার-কেসটিকে কীভাবে সম্বোধন করা যায়:

# TEST 4
my_thread = ThreadWithReturn(target=giveMe, args=(None,), kwargs={'seconds': 5})
my_thread.start()
returned = my_thread.join(timeout=random.randint(1, 10))

if my_thread.isAlive():
    # returned is None because join() timed out
    # this also means that giveMe() is still running in the background
    pass
    # handle this based on your app's logic
else:
    # join() is finished, and so is giveMe()
    # BUT we could also be in a race condition, so we need to update returned, just in case
    returned = my_thread.join()

আপনি কি পাইথন 3 এর সমতুল্য_ড্রেড_টারজেটটি জানেন? পাইথন 3 এ সেই বৈশিষ্ট্যটির অস্তিত্ব নেই।
গ্রেইসেজ

আমি থ্রেডিং.পি ফাইলটিতে দেখলাম, এটি সরে গেছে এটি _ ডেটেজ (অন্যান্য বৈশিষ্ট্যগুলি একইভাবে নামকরণ করা হয়েছে)।
গ্রেইসেজ

আপনি থ্রেড ক্লাসের ব্যক্তিগত ভেরিয়েবল ব্যবহারের এড়াতে পারে, যদি আপনি সংরক্ষণ target, argsএবং kwargsআর্গুমেন্ট init আপনার ক্লাসে সদস্য ভেরিয়েবল হিসেবে।
টোলি

@ গ্রেজেজ আমার উত্তর দেখুন, আমি এই ব্লকটি নীচে
পাইথন

@ গ্রেজেজ উত্তর এখন পাই 2 এবং পাই 3
ইউজার 2426679

15

সারি ব্যবহার:

import threading, queue

def calc_square(num, out_queue1):
  l = []
  for x in num:
    l.append(x*x)
  out_queue1.put(l)


arr = [1,2,3,4,5,6,7,8,9,10]
out_queue1=queue.Queue()
t1=threading.Thread(target=calc_square, args=(arr,out_queue1))
t1.start()
t1.join()
print (out_queue1.get())

1
সংক্ষিপ্ত এবং মিষ্টি সত্যিই এই একাকীকরণ পছন্দ। আপনার ফাংশন একটি ইনপুট কিউ সার্চ, এবং আপনাকে যুক্ত করে থাকেন out_queue1তোমাদের উপর লুপ করতে হবে out_queue1.get()এবং Queue.Empty ব্যতিক্রম ধরা: ret = [] ; try: ; while True; ret.append(out_queue1.get(block=False)) ; except Queue.Empty: ; pass। লাইন ব্রেক অনুকরণ করার জন্য আধা-কলোন।
সাস্টারসেল

6

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

import threading

class ThreadWorker():
    '''
    The basic idea is given a function create an object.
    The object can then run the function in a thread.
    It provides a wrapper to start it,check its status,and get data out the function.
    '''
    def __init__(self,func):
        self.thread = None
        self.data = None
        self.func = self.save_data(func)

    def save_data(self,func):
        '''modify function to save its returned data'''
        def new_func(*args, **kwargs):
            self.data=func(*args, **kwargs)

        return new_func

    def start(self,params):
        self.data = None
        if self.thread is not None:
            if self.thread.isAlive():
                return 'running' #could raise exception here

        #unless thread exists and is alive start or restart it
        self.thread = threading.Thread(target=self.func,args=params)
        self.thread.start()
        return 'started'

    def status(self):
        if self.thread is None:
            return 'not_started'
        else:
            if self.thread.isAlive():
                return 'running'
            else:
                return 'finished'

    def get_results(self):
        if self.thread is None:
            return 'not_started' #could return exception
        else:
            if self.thread.isAlive():
                return 'running'
            else:
                return self.data

def add(x,y):
    return x +y

add_worker = ThreadWorker(add)
print add_worker.start((1,2,))
print add_worker.status()
print add_worker.get_results()

আপনি কিভাবে একটি ব্যতিক্রম পরিচালনা করবেন? আসুন ধরুন অ্যাড ফাংশনটি দেওয়া হয়েছিল এবং int এবং একটি str। সমস্ত থ্রেড ব্যর্থ হবে বা শুধুমাত্র একটি ব্যর্থ হবে?
ব্যবহারকারী 1745713


4

@ জ্যাকবিসিংগার উত্তরের উপর আইমানের মন্তব্য বিবেচনায় নিয়ে আমি এটি বিভিন্ন সংখ্যক থ্রেড নিয়ে রেকর্ড করেছি:

from multiprocessing.pool import ThreadPool

def foo(bar, baz):
    print 'hello {0}'.format(bar)
    return 'foo' + baz

numOfThreads = 3 
results = []

pool = ThreadPool(numOfThreads)

for i in range(0, numOfThreads):
    results.append(pool.apply_async(foo, ('world', 'foo'))) # tuple of args for foo)

# do some other stuff in the main process
# ...
# ...

results = [r.get() for r in results]
print results

pool.close()
pool.join()

চিয়ার্স,

গাই।


2

থ্রেডেড ফাংশনটির সুযোগের উপরে আপনি একটি পরিবর্তনীয়কে সংজ্ঞায়িত করতে পারেন এবং ফলাফলটি এতে যুক্ত করতে পারেন। (আমি কোডটি পাইথন 3 সামঞ্জস্যপূর্ণ রূপেও পরিবর্তন করেছি)

returns = {}
def foo(bar):
    print('hello {0}'.format(bar))
    returns[bar] = 'foo'

from threading import Thread
t = Thread(target=foo, args=('world!',))
t.start()
t.join()
print(returns)

এই ফিরে আসে {'world!': 'foo'}

আপনি যদি আপনার ফলাফলগুলির কী হিসাবে ফাংশন ইনপুট ব্যবহার করেন তবে প্রতিটি অনন্য ইনপুট ফলাফলগুলিতে প্রবেশের গ্যারান্টিযুক্ত


2

আমি এই মোড়কটি ব্যবহার করছি, যা স্বাচ্ছন্দ্যে কোনও চলার জন্য কোনও ফাংশন ঘুরিয়ে দেয় Thread- এর ফেরতের মান বা ব্যতিক্রমের যত্ন নেওয়া taking এটি Queueওভারহেড যোগ করে না ।

def threading_func(f):
    """Decorator for running a function in a thread and handling its return
    value or exception"""
    def start(*args, **kw):
        def run():
            try:
                th.ret = f(*args, **kw)
            except:
                th.exc = sys.exc_info()
        def get(timeout=None):
            th.join(timeout)
            if th.exc:
                raise th.exc[0], th.exc[1], th.exc[2] # py2
                ##raise th.exc[1] #py3                
            return th.ret
        th = threading.Thread(None, run)
        th.exc = None
        th.get = get
        th.start()
        return th
    return start

ব্যবহারের উদাহরণ

def f(x):
    return 2.5 * x
th = threading_func(f)(4)
print("still running?:", th.is_alive())
print("result:", th.get(timeout=1.0))

@threading_func
def th_mul(a, b):
    return a * b
th = th_mul("text", 2.5)

try:
    print(th.get())
except TypeError:
    print("exception thrown ok.")

threadingমডিউল নোট

আরামদায়ক রিটার্ন মান এবং একটি থ্রেডযুক্ত ফাংশন ব্যতিক্রম হ্যান্ডলিং একটি ঘন ঘন "পাইথোনিক" প্রয়োজন এবং প্রকৃতপক্ষে threadingমডিউলটি ইতিমধ্যে দেওয়া উচিত - সম্ভবত সরাসরি স্ট্যান্ডার্ড Threadশ্রেণিতে। ThreadPoolসরল কাজের জন্য অনেক বেশি ওভারহেড রয়েছে - 3 পরিচালনা থ্রেড, প্রচুর আমলাতন্ত্র। দুর্ভাগ্যক্রমে Threadলেআউটটি মূলত জাভা থেকে অনুলিপি করা হয়েছিল - যা আপনি উদাহরণস্বরূপ এখনও অব্যর্থ 1 ম (!) কনস্ট্রাক্টর প্যারামিটার থেকে দেখেছেন group


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

1

আপনার লক্ষ্যটিকে
1 এ সংজ্ঞায়িত করুন ) একটি যুক্তি নিন q
2) কোনও বিবৃতি return fooদিয়ে প্রতিস্থাপন করুনq.put(foo); return

সুতরাং একটি ফাংশন

def func(a):
    ans = a * a
    return ans

হবে

def func(a, q):
    ans = a * a
    q.put(ans)
    return

এবং তারপরে আপনি যেমন এগিয়ে যেতে হবে

from Queue import Queue
from threading import Thread

ans_q = Queue()
arg_tups = [(i, ans_q) for i in xrange(10)]

threads = [Thread(target=func, args=arg_tup) for arg_tup in arg_tups]
_ = [t.start() for t in threads]
_ = [t.join() for t in threads]
results = [q.get() for _ in xrange(len(threads))]

এবং আপনি এটি তৈরি করতে ফাংশন সজ্জকার / মোড়ক ব্যবহার করতে পারেন যাতে আপনি আপনার বিদ্যমান ফাংশনগুলি targetপরিবর্তন না করে ব্যবহার করতে পারেন তবে এই বেসিক স্কিমটি অনুসরণ করুন।


এটি হওয়া উচিতresults = [ans_q.get() for _ in xrange(len(threads))]
হেমন্ত এইচ কুমার

1

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

#!/usr/bin/env python3

import threading
# use Queue for python2
import queue
import random

LETTERS = 'abcdefghijklmnopqrstuvwxyz'
LETTERS = [ x for x in LETTERS ]

NUMBERS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

def randoms(k, q):
    result = dict()
    result['letter'] = random.choice(LETTERS)
    result['number'] = random.choice(NUMBERS)
    q.put({k: result})

threads = list()
q = queue.Queue()
results = dict()

for name in ('alpha', 'oscar', 'yankee',):
    threads.append( threading.Thread(target=randoms, args=(name, q)) )
    threads[-1].start()
_ = [ t.join() for t in threads ]
while not q.empty():
    results.update(q.get())

print(results)

1

গাইসফ্টের ধারণাটি দুর্দান্ত, তবে আমি মনে করি যে বিষয়টি অবশ্যই থ্রেড থেকে উত্তরাধিকার সূত্রে গ্রহণ করতে হবে না এবং ()) ইন্টারফেস থেকে অপসারণ করা যেতে পারে:

from threading import Thread
import queue
class ThreadWithReturnValue(object):
    def __init__(self, target=None, args=(), **kwargs):
        self._que = queue.Queue()
        self._t = Thread(target=lambda q,arg1,kwargs1: q.put(target(*arg1, **kwargs1)) ,
                args=(self._que, args, kwargs), )
        self._t.start()

    def join(self):
        self._t.join()
        return self._que.get()


def foo(bar):
    print('hello {0}'.format(bar))
    return "foo"

twrv = ThreadWithReturnValue(target=foo, args=('world!',))

print(twrv.join())   # prints foo

0

একটি সাধারণ সমাধান হ'ল আপনার ফাংশনটি fooডেকরেটারের মতো মোড়ানো

result = queue.Queue()

def task_wrapper(*args):
    result.put(target(*args))

তারপরে পুরো কোডটি দেখতে পারা যায়

result = queue.Queue()

def task_wrapper(*args):
    result.put(target(*args))

threads = [threading.Thread(target=task_wrapper, args=args) for args in args_list]

for t in threads:
    t.start()
    while(True):
        if(len(threading.enumerate()) < max_num):
            break
for t in threads:
    t.join()
return result

বিঃদ্রঃ

একটি গুরুত্বপূর্ণ বিষয় হ'ল রিটার্নের মানগুলি সীমাহীন হতে পারে । (আসলে, এটি return valueঅগত্যা রক্ষা করা হয় না queue, যেহেতু আপনি নির্বিচারে থ্রেড-নিরাপদ ডেটা কাঠামো চয়ন করতে পারেন )


0

শুধু বৈশ্বিক চলক কেন ব্যবহার করবেন না?

import threading


class myThread(threading.Thread):
    def __init__(self, ind, lock):
        threading.Thread.__init__(self)
        self.ind = ind
        self.lock = lock

    def run(self):
        global results
        with self.lock:
            results.append(self.ind)



results = []
lock = threading.Lock()
threads = [myThread(x, lock) for x in range(1, 4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print(results)

0

Kindall এর উত্তর Python3 মধ্যে

class ThreadWithReturnValue(Thread):
    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs={}, *, daemon=None):
        Thread.__init__(self, group, target, name, args, kwargs, daemon)
        self._return = None 

    def run(self):
        try:
            if self._target:
                self._return = self._target(*self._args, **self._kwargs)
        finally:
            del self._target, self._args, self._kwargs 

    def join(self,timeout=None):
        Thread.join(self,timeout)
        return self._return

-2

যদি কোনও ফাংশনের কল থেকে কেবল সত্য বা মিথ্যা প্রমাণিত করতে হয় তবে একটি সহজ সমাধান আমি খুঁজে পাই যা একটি বিশ্বব্যাপী তালিকা আপডেট করে।

import threading

lists = {"A":"True", "B":"True"}

def myfunc(name: str, mylist):
    for i in mylist:
        if i == 31:
            lists[name] = "False"
            return False
        else:
            print("name {} : {}".format(name, i))

t1 = threading.Thread(target=myfunc, args=("A", [1, 2, 3, 4, 5, 6], ))
t2 = threading.Thread(target=myfunc, args=("B", [11, 21, 31, 41, 51, 61], ))
t1.start()
t2.start()
t1.join()
t2.join()

for value in lists.values():
    if value == False:
        # Something is suspicious 
        # Take necessary action 

থ্রেডগুলির মধ্যে যে কোনও একটি প্রয়োজনীয় পদক্ষেপ নেওয়ার জন্য কোনও ভ্রান্ত স্থিতি ফিরে পেয়েছিল কিনা তা আপনি এটি সন্ধান করতে সহায়তা করেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.