Ответ 1
Если я правильно понял, вы хотите запустить функцию в отдельном потоке? Существует несколько способов сделать это. Но в основном вы завершаете свою функцию следующим образом:
class MyClass:
somevar = 'someval'
def _func_to_be_threaded(self):
# main body
def func_to_be_threaded(self):
threading.Thread(target=self._func_to_be_threaded).start()
Его можно укоротить декоратором:
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class MyClass:
somevar = 'someval'
@threaded
def func_to_be_threaded(self):
# main body
Изменить Обновленная версия с дескриптором:
def threaded(fn):
def wrapper(*args, **kwargs):
thread = threading.Thread(target=fn, args=args, kwargs=kwargs)
thread.start()
return thread
return wrapper
class MyClass:
somevar = 'someval'
@threaded
def func_to_be_threaded(self):
print 'xyz'
Это можно использовать следующим образом:
>>> my_obj = MyClass()
>>> handle = my_obj.func_to_be_threaded()
>>> handle.join()
Теперь можно расширить его еще больше, если вы хотите вернуть значение из функции. Рассмотрим это:
from threading import Thread
from concurrent.futures import Future
def call_with_future(fn, future, args, kwargs):
try:
result = fn(*args, **kwargs)
future.set_result(result)
except Exception as exc:
future.set_exception(exc)
def threaded(fn):
def wrapper(*args, **kwargs):
future = Future()
Thread(target=call_with_future, args=(fn, future, args, kwargs)).start()
return future
return wrapper
class MyClass:
@threaded
def get_my_value(self):
return 1
>>> my_obj = MyClass()
>>> fut = my_obj.get_my_value() # this will run in a separate thread
>>> fut.result() # will block until result is computed
1
Если у вас нет concurrent.futures.Future class (потому что, например, вы используете Python2.7 или старше), вы можете использовать эту упрощенную реализацию:
from threading import Event
class Future(object):
def __init__(self):
self._ev = Event()
def set_result(self, result):
self._result = result
self._ev.set()
def set_exception(self, exc):
self._exc = exc
self._ev.set()
def result(self):
self._ev.wait()
if hasattr(self, '_exc'):
raise self._exc
return self._result
Я советую читать через concurrent.futures модуль, так как у него много опрятных инструментов. Например, класс Thread
должен быть заменен экземпляром ThreadPoolExecutor
для ограничения concurrency (например, вы не хотите спамить потоки 10k). Также с ThreadPoolExecutor
код еще проще (и меньше подвержен ошибкам):
from concurrent.futures import ThreadPoolExecutor
tp = ThreadPoolExecutor(10) # max 10 threads
def threaded(fn):
def wrapper(*args, **kwargs):
return tp.submit(fn, *args, **kwargs) # returns Future object
return wrapper
Просто помните, что вы должны tp.shutdown()
после выполнения всей параллельной работы.