스레드에서 반환 값을 가져오는 방법은 무엇입니까?
수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.
제가 본 한 가지 방법은 목록이나 사전과 같은 가변 객체를 인덱스나 다른 종류의 식별자와 함께 스레드의 생성자에게 전달하는 것입니다.그런 다음 스레드는 해당 개체의 전용 슬롯에 결과를 저장할 수 있습니다.예:
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하지만 하지만 그것은 효과가 있다.
Python 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):
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
, FWIW, »multiprocessing은 이은위멋인가있를지습다니고스이터모듈페를 하여 이를 를 가지고 .Poolclass. 클스를 . 그리고 만약 당신이 프로세스보다 스레드를 고수하고 싶다면, 당신은 그냥 사용할 수 있습니다.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.
Python 3.2+에서 stdlib 모듈은 더 높은 수준의 API를 제공합니다.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)
Jake의 대답은 좋지만 스레드 풀(필요한 스레드 수는 모르지만 필요에 따라 생성)을 사용하지 않으려면 기본 제공 큐를 사용하여 스레드 간에 정보를 전송하는 것이 좋습니다.스레드 안전을 제공하는 큐 클래스입니다.
스레드 풀과 유사한 방식으로 작동하도록 하기 위해 다음과 같은 장식기를 만들었습니다.
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
장식된 함수는 호출될 때마다 새 스레드를 만들고 결과를 수신할 대기열이 포함된 스레드 개체를 반환합니다.
갱신하다
이 답변을 게시한 지 꽤 오래되었지만 여전히 조회 수가 있으므로 최신 버전의 Python에서 수행하는 방식을 반영하여 업데이트하려고 생각했습니다.
모듈에 병렬 작업을 위한 고급 인터페이스를 제공하는 Python 3.2가 추가되었습니다.제공합니다.ThreadPoolExecutor그리고.ProcessPoolExecutor동일한 api로 스레드 또는 프로세스 풀을 사용할 수 있습니다.
한은 api에 입니다.Executor개체를 반환합니다. 이 개체는 사용자가 제출한 호출부호의 반환 값으로 완료됩니다.
이를은붙합니를 붙이게 .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
Python 3.4+를 사용하는 경우 이 방법(및 일반적으로 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
그런 다음 CPU 집약적인 코드나 차단 코드를 이벤트 루프 스레드에서 밀어내야 할 때마다 장식된 기능에 넣을 수 있습니다.
@threadpool
def some_long_calculation():
...
# this will suspend while the function is executed on a threadpool
result = await some_long_calculation()
기존 코드를 변경할 필요가 없는 또 다른 솔루션:
import Queue # Python 2.x
#from queue import Queue # Python 3.x
from threading import Thread
def foo(bar):
print 'hello {0}'.format(bar) # Python 2.x
#print('hello {0}'.format(bar)) # Python 3.x
return 'foo'
que = Queue.Queue() # Python 2.x
#que = Queue() # Python 3.x
t = Thread(target=lambda q, arg1: q.put(foo(arg1)), args=(que, 'world!'))
t.start()
t.join()
result = que.get()
print result # Python 2.x
#print(result) # Python 3.x
또한 멀티 스레드 환경에 쉽게 조정할 수 있습니다.
import Queue # Python 2.x
#from queue import Queue # Python 3.x
from threading import Thread
def foo(bar):
print 'hello {0}'.format(bar) # Python 2.x
#print('hello {0}'.format(bar)) # Python 3.x
return 'foo'
que = Queue.Queue() # Python 2.x
#que = Queue() # Python 3.x
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 # Python 2.x
#print(result) # Python 3.x
업데이트:
스레드의 결과를 저장할 수 있는 훨씬 간단하고 간결한 방법이 있으며, 인터페이스를 거의 동일하게 유지할 수 있는 방법이 있다고 생각합니다.threading.Threadclass -를 하지 않았습니다): class (class):
import threading
class ConciseResult(threading.Thread):
def run(self):
self.result = self._target(*self._args, **self._kwargs)
import threading
class ConciseRobustResult(threading.Thread):
def run(self):
try:
if self._target is not None:
self.result = self._target(*self._args, **self._kwargs)
finally:
# Avoid a refcycle if the thread is running a function with
# an argument that has a member that points to the thread.
del self._target, self._args, self._kwargs
간략한 설명: 우리는 단지 그것을 무시합니다.run의 threading.Thread다른 것은 수정하지 않습니다.이를 통해 다른 모든 것을 사용할 수 있습니다.threading.Thread클래스는 원래 게시물에서 수행하는 방식으로 속성 할당이나 사용자 지정 속성 수정과 같은 잠재적인 에지 사례를 누락할 염려 없이 우리에게 도움이 됩니다.
우리는 우리가 단지 수정하는 것을 확인할 수 있습니다.run의 을 보는 help(ConciseResult)그리고.help(ConciseRobustResult)아에포속유메설일서함한/된드성/명자래설에 포함된 한 메서드Methods defined here:이라run그리고 다른 모든 것들은 유전된 것들로부터 옵니다.threading.Thread 클래스)Methods inherited from threading.Thread:섹션)을 클릭합니다.
아래 예제 코드를 사용하여 이러한 구현 중 하나를 테스트하려면 다음과 같이 대체합니다.ConciseResult또는ConciseRobustResult위해서ThreadWithResult에 시대에main아래의 기능.
의 폐쇄 기능을 사용한 원본 게시물init방법:
제가 찾은 대부분의 답변은 길고 다른 모듈이나 고급 파이썬 기능에 익숙해야 하며, 답변이 말하는 모든 것에 이미 익숙하지 않으면 누군가에게 다소 혼란스러울 것입니다.
단순화된 접근 방식을 위한 작업 코드:
import threading
class ThreadWithResult(threading.Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None):
def function():
self.result = target(*args, **kwargs)
super().__init__(group=group, target=function, name=name, daemon=daemon)
코드 예제:
import time, random
def function_to_thread(n):
count = 0
while count < 3:
print(f'still running thread {n}')
count +=1
time.sleep(3)
result = random.random()
print(f'Return value of thread {n} should be: {result}')
return result
def main():
thread1 = ThreadWithResult(target=function_to_thread, args=(1,))
thread2 = ThreadWithResult(target=function_to_thread, args=(2,))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(thread1.result)
print(thread2.result)
main()
설명:저는 작업을 크게 단순화하고 싶었기 때문에,ThreadWithResult.threading.Thread 함수 포내 수function__init__값을 저장할 스레드 함수를 호출하고 중첩 함수의 결과를 인스턴스 속성으로 저장합니다.self.result스레드 실행이 완료된 후.
를 만드는 은 이인턴를만것다은인동것다만니의 것과 .threading.Thread를 새스드에함다전음달다니합로에 합니다.target및할 수 를 사용합니다.args에 대한 인수 및 kwargs논쟁.
예.
my_thread = ThreadWithResult(target=my_function, args=(arg1, arg2, arg3))
저는 이것이 대다수의 대답보다 훨씬 이해하기 쉬우며, 이 접근법은 추가적인 수입이 필요하지 않다고 생각합니다!나는 포함시켰습니다.time그리고.random모듈을 사용하여 스레드의 동작을 시뮬레이션하지만 원래 질문에서 질문한 기능을 달성할 필요는 없습니다.
질문이 있은 지 한참 후에 제가 이 바보 같은 소리에 대답하고 있다는 것을 알지만, 이것이 앞으로 더 많은 사람들에게 도움이 될 수 있기를 바랍니다!
편집: 위의 동일한 코드에 액세스하여 프로젝트 간에 재사용할 수 있도록 PyPI 패키지를 만들었습니다(GitHub 코드는 여기에 있습니다).PyPI 패키지는 다음을 완전히 확장합니다.threading.Thread사용하여 래스클에서 할 수 . 설정할 속성을 설정할 수 있습니다.threading.thread에서.ThreadWithResult수업도!
위의 원래 답변은 이 하위 클래스 뒤에 있는 주요 아이디어에 대해 설명하지만, 자세한 내용은 여기에서 (모듈 문서 문자열에서) 더 자세한 설명을 참조하십시오.
빠른 사용 예:
pip3 install -U save-thread-result # MacOS/Linux
pip install -U save-thread-result # Windows
python3 # MacOS/Linux
python # Windows
from save_thread_result import ThreadWithResult
# As of Release 0.0.3, you can also specify values for
#`group`, `name`, and `daemon` if you want to set those
# values manually.
thread = ThreadWithResult(
target = my_function,
args = (my_function_arg1, my_function_arg2, ...)
kwargs = {my_function_kwarg1: kwarg1_value, my_function_kwarg2: kwarg2_value, ...}
)
thread.start()
thread.join()
if getattr(thread, 'result', None):
print(thread.result)
else:
# thread.result attribute not set - something caused
# the thread to terminate BEFORE the thread finished
# executing the function passed in through the
# `target` argument
print('ERROR! Something went wrong while executing this thread, and the function you passed in did NOT complete!!')
# seeing help about the class and information about the threading.Thread super class methods and attributes available:
help(ThreadWithResult)
패리스 / 킨들의 대답 join/returnPython 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클래스는 Python 3에서 다르게 구현됩니다.
저는 킨들의 답변을 훔쳐서 조금 치웠습니다.
주요 부분은 제한 시간을 처리하기 위해 *args 및 **kwargs를 join()에 추가하는 것입니다.
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
아래의 업데이트된 답변
이것은 제가 가장 많이 투표한 답변입니다. 그래서 저는 py2와 py3 모두에서 실행될 코드로 업데이트하기로 결정했습니다.
또한 이 질문에 대해 Thread.join()에 대한 이해가 부족한 답변이 많이 보입니다.일부는 완전히 처리하지 못합니다.timeout ( 할 수 있는 대상 가 있는 경우 해야 할 . 그러나 (1) 반환할 수 있는 대상 함수가 있는 경우 인스턴스와 관련하여 주의해야 할 코너 케이스도 있습니다.None그리고 (2) 당신은 또한 통과합니다.timeout케이스를 하려면 " 4하십시오.이 코너 사례를 이해하려면 "테스트 4"를 참조하십시오.
py2 및 py3에서 작동하는 ThreadWithReturn 클래스:
import sys
from threading import Thread
from builtins import super # https://stackoverflow.com/a/30159479
_thread_target_key, _thread_args_key, _thread_kwargs_key = (
('_target', '_args', '_kwargs')
if sys.version_info >= (3, 0) else
('_Thread__target', '_Thread__args', '_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 target is not 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에서 발생할 수 있는 코너 케이스를 식별할 수 있습니까?
문제는 giveMe()가 없음을 반환할 것으로 예상하지만(테스트 2 참조), 시간이 초과되면 join()이 없음을 반환할 것으로 예상한다는 것입니다.
returned is None다음 중 하나를 의미합니다.
그게 바로 내게 돌려준 것입니다.
join(가입) 시간 초과
giveMe()가 항상 None을 반환한다는 것을 알고 있기 때문에 이 예제는 사소한 것입니다.그러나 실제 사례(대상이 합법적으로 "없음" 또는 "다른 것"을 반환할 수 있는 경우)에서는 무슨 일이 일어났는지 명시적으로 확인하고 싶습니다.
다음은 이 코너 케이스를 해결하는 방법입니다.
# 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()
대기열 사용:
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())
그 문제에 대한 나의 해결책은 함수와 스레드를 클래스에 랩하는 것입니다.풀, 대기열 또는 c 유형 변수 전달을 사용할 필요가 없습니다.또한 비차단 기능입니다.대신 상태를 확인합니다.코드 끝에서 사용하는 방법의 예를 참조하십시오.
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()
@JakeBiesinger 답변에 대한 @iman 코멘트를 고려하여 다양한 스레드 수를 갖도록 재구성했습니다.
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()
저는 이 포장지를 사용하고 있는데, 이 포장지는 어떤 기능이든 편안하게 작동합니다.Thread반환 값 또는 예외를 처리합니다.추가되지 않습니다.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 컨트롤 모듈
값 및 한 "이며, 사기파편반빈값처및예리번 "는토닉이며", ▁the▁is▁▁by▁be▁handling▁indeed▁offered▁already▁ofpy▁value"다합니▁function▁and▁&▁should▁exception▁need에서 제공되어야 합니다.threading모듈 - 표준에 직접 포함될 수 있습니다.Thread학급.ThreadPool단순한 작업에는 너무 많은 오버헤드가 있습니다. 3가지 스레드 관리, 많은 관료주의.도 불하게도행.Thread원래 를 들어 첫 번째 매개변수에서 되었습니다. 보시는 바와 같이 여전히 쓸모없는 첫 번째(!) 생성자 매개 변수에서 복사되었습니다.group.
언급된 모든 종류의 솔루션을 기반으로 Python3에서 작동하는 보다 일반적인 솔루션을 소개합니다.
import threading
class ThreadWithReturnValue(threading.Thread):
def __init__(self, *init_args, **init_kwargs):
threading.Thread.__init__(self, *init_args, **init_kwargs)
self._return = None
def run(self):
self._return = self._target(*self._args, **self._kwargs)
def join(self):
threading.Thread.join(self)
return self._return
사용.
th = ThreadWithReturnValue(target=requests.get, args=('http://www.google.com',))
th.start()
response = th.join()
response.status_code # => 200
join 되돌아가다None저는 당신이 서브클래스를 해야 한다고 생각합니다.Thread반송 코드 등을 처리할 수 있습니다.
스레드 함수의 범위 위에 변수를 정의하고 결과를 추가할 수 있습니다. (또한 코드를 python3와 호환되도록 수정했습니다.)
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'}
함수 입력을 결과 딕트의 키로 사용하면 모든 고유 입력이 결과에 입력됩니다.
제가 발견한 가장 짧고 간단한 방법은 Python 클래스와 동적 속성을 활용하는 것입니다.에서 음을사용생스컨내현에텍재스있검수를 사용하여 할 수 .threading.current_thread()속성에 반환 값을 할당합니다.
import threading
def some_target_function():
# Your code here.
threading.current_thread().return_value = "Some return value."
your_thread = threading.Thread(target=some_target_function)
your_thread.start()
your_thread.join()
return_value = your_thread.return_value
print(return_value)
당신의 를 표를정니목다로하세요.
을 q
문을 합니다.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수정하지 않고 이 기본 계획을 따릅니다.
GuySoft의 아이디어는 훌륭하지만, 객체가 스레드에서 상속될 필요는 없고 인터페이스에서 start()를 제거할 수 있다고 생각합니다.
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
이것은 꽤 오래된 질문이지만, 저에게 효과가 있고 개발 프로세스에 도움이 되는 간단한 솔루션을 공유하고 싶었습니다.
함수인 "새로운" 대상 함수, "새로운" 대상 함수,inner원래 함수의 결과를 할당하는 것입니다(을 통해 전달됨).__init__ to 능에한대기▁result폐쇄라는 것을 통한 래퍼의 인스턴스 속성입니다.
이를 통해 래퍼 클래스는 호출자가 언제든지 액세스할 수 있는 반환 값을 보유할 수 있습니다.
참고: 이 메서드는 다음과 같은 임의의 메서드나 개인 메서드를 사용할 필요가 없습니다.threading.Thread항복 함수가 고려되지 않았지만 등급.
맛있게 드세요!
from threading import Thread as _Thread
class ThreadWrapper:
def __init__(self, target, *args, **kwargs):
self.result = None
self._target = self._build_threaded_fn(target)
self.thread = _Thread(
target=self._target,
*args,
**kwargs
)
def _build_threaded_fn(self, func):
def inner(*args, **kwargs):
self.result = func(*args, **kwargs)
return inner
또실행수있다니를 도 있습니다.pytest되어 있는 ) 를 보여줍니다
import time
from commons import ThreadWrapper
def test():
def target():
time.sleep(1)
return 'Hello'
wrapper = ThreadWrapper(target=target)
wrapper.thread.start()
r = wrapper.result
assert r is None
time.sleep(2)
r = wrapper.result
assert r == 'Hello'
언급했듯이 멀티프로세싱 풀은 기본 스레드보다 훨씬 느립니다.일부 답변에서 제안한 대로 대기열을 사용하는 것은 매우 효과적인 대안입니다.사전과 함께 사용하여 많은 작은 스레드를 실행하고 사전과 결합하여 여러 답변을 복구할 수 있습니다.
#!/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)
여기 제가 @Kindall의 답변으로 만든 버전이 있습니다.
이 버전에서는 새 스레드를 생성하기 위해 인수와 함께 명령을 입력하기만 하면 됩니다.
이것은 Python 3.8로 만들어졌습니다.
from threading import Thread
from typing import Any
def test(plug, plug2, plug3):
print(f"hello {plug}")
print(f'I am the second plug : {plug2}')
print(plug3)
return 'I am the return Value!'
def test2(msg):
return f'I am from the second test: {msg}'
def test3():
print('hello world')
def NewThread(com, Returning: bool, *arguments) -> Any:
"""
Will create a new thread for a function/command.
:param com: Command to be Executed
:param arguments: Arguments to be sent to Command
:param Returning: True/False Will this command need to return anything
"""
class NewThreadWorker(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
ntw = NewThreadWorker(target = com, args = (*arguments,))
ntw.start()
if Returning:
return ntw.join()
if __name__ == "__main__":
print(NewThread(test, True, 'hi', 'test', test2('hi')))
NewThread(test3, True)
를 사용하여 다음과 같이 값을 반환할 수 있습니다.
from multiprocessing.pool import ThreadPool
def test(num1, num2):
return num1 + num2
pool = ThreadPool(processes=1) # Here
result = pool.apply_async(test, (2, 3)) # Here
print(result.get()) # 5
또한 다음과 같이 의 값을 반환할 수도 있습니다.
from concurrent.futures import ThreadPoolExecutor
def test(num1, num2):
return num1 + num2
with ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(test, 2, 3) # Here
print(future.result()) # 5
대신 아래와 같이 배열을 사용할 수 있습니다.
from threading import Thread
def test(num1, num2, r):
r[0] = num1 + num2 # Instead of "return"
result = [None] # Here
thread = Thread(target=test, args=(2, 3, result))
thread.start()
thread.join()
print(result[0]) # 5
대신 아래와 같이 대기열을 사용할 수도 있습니다.
from threading import Thread
import queue
def test(num1, num2, q):
q.put(num1 + num2) # Instead of "return"
queue = queue.Queue() # Here
thread = Thread(target=test, args=(2, 3, queue))
thread.start()
thread.join()
print(queue.get()) # '5'
한 가지 일반적인 해결책은 당신의 기능을 포장하는 것입니다.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임의의 스레드 세이프 데이터 구조를 선택할 수 있으므로 )
Python3에서의 Kindall의 대답.
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
이 스레드가 오래된 것은 알지만, 저도 같은 문제에 직면했습니다.사용할 의사가 있는 경우thread.join()
import threading
class test:
def __init__(self):
self.msg=""
def hello(self,bar):
print('hello {}'.format(bar))
self.msg="foo"
def main(self):
thread = threading.Thread(target=self.hello, args=('world!',))
thread.start()
thread.join()
print(self.msg)
g=test()
g.main()
최선의 방법은...전역 변수를 정의한 다음 스레드 함수에서 변수를 변경합니다.전달하거나 다시 검색할 항목 없음
from threading import Thread
# global var
random_global_var = 5
def function():
global random_global_var
random_global_var += 1
domath = Thread(target=function)
domath.start()
domath.join()
print(random_global_var)
# result: 6
언급URL : https://stackoverflow.com/questions/6893968/how-to-get-the-return-value-from-a-thread
'programing' 카테고리의 다른 글
| 도커 실행을 통해 셸 스크립트에 인수를 전달하는 방법 (0) | 2023.05.09 |
|---|---|
| VB의 여러 줄에 걸친 단일 문입니다.밑줄 문자가 없는 NET (0) | 2023.05.09 |
| SQL 오름차순 정렬 시 null 값이 마지막에 오도록 하는 방법 (0) | 2023.05.09 |
| 메이븐 다운로드에는 .last가 확장으로 업데이트되었습니다. (0) | 2023.05.09 |
| LINQ를 사용하여 목록이 비어 있는지 확인하는 중 (0) | 2023.05.09 |