类内的 Python 线程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19846332/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python Threading inside a class
提问by Niels
I recently started with python's threading module. After some trial and error I managed to get basic threading working using the following sample code given in most tutorials.
我最近开始使用 python 的线程模块。经过一些试验和错误,我设法使用大多数教程中给出的以下示例代码使基本线程工作。
class SomeThread(threading.Thread):
def __init__(self, count):
threading.Thread.__init__(self)
def run(self):
print "Do something"
My problem is: I have a Class that has class variables and a function that I want to be run in a separate thread. However the function uses class variables and also writes to class variables. Like so:
我的问题是:我有一个包含类变量的类和一个我想在单独线程中运行的函数。然而,该函数使用类变量并写入类变量。像这样:
class MyClass:
somevar = 'someval'
def func_to_be_threaded(self):
# Uses other class functions
# Do something with class variables
So how would I essentially 'put the thread class in MyClass'. So that if MyClass().func_to_threaded() is called it would run in a thread.
那么我基本上如何“将线程类放在 MyClass 中”。因此,如果调用 MyClass().func_to_threaded() 它将在线程中运行。
采纳答案by freakish
If I understand correctly you want to run a function in a separate thread? There are several ways to do that. But basically you wrap your function like this:
如果我理解正确,您想在单独的线程中运行一个函数?有几种方法可以做到这一点。但基本上你这样包装你的函数:
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()
It can be shortened with a decorator:
它可以用装饰器缩短:
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
EditUpdated version with a handle:
使用句柄编辑更新版本:
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'
This can be used as follows:
这可以按如下方式使用:
>>> my_obj = MyClass()
>>> handle = my_obj.func_to_be_threaded()
>>> handle.join()
Now it is possible to extend it even more if you wish to return a value from the function. Consider this:
如果您希望从函数返回一个值,现在可以进一步扩展它。考虑一下:
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
If you don't have concurrent.futures.Future class(because for example you are using Python2.7 or older) then you can use this simplified implementation:
如果您没有concurrent.futures.Future 类(因为例如您使用的是 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
I advice reading through concurrent.futuresmodule since it has a lot of neat tools. For example Thread
class should be replaced with a ThreadPoolExecutor
instance to limit concurrency (e.g. you don't want to spam 10k threads). Also with ThreadPoolExecutor
the code is even simplier (and less error prone):
我建议通读concurrent.futures模块,因为它有很多简洁的工具。例如,Thread
类应该替换为一个ThreadPoolExecutor
实例以限制并发(例如,您不想向 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
Just remember you have to tp.shutdown()
after you're done with all parallel work.
请记住,tp.shutdown()
在完成所有并行工作后,您必须这样做。
回答by ndpu
You can pass class instance to the thread:
您可以将类实例传递给线程:
class SomeThread(threading.Thread):
def __init__(self, count, instance):
threading.Thread.__init__(self)
self.instance = instance
def run(self):
print "Do something"
self.instance.some_param = data
self.instance.some_function()
回答by Matt
I'm fairly certain that you can't make a single function threaded.
我相当确定您不能将单个函数设为线程。
The whole class will be threaded (sort of). When you instantiate the object, its __init__
will be called on another thread, and then when you call start()
on that object, its run()
will be called once, on another thread.
整个班级都将被线程化(有点)。当您实例化对象时,__init__
它将在另一个线程上调用,然后当您调用start()
该对象时,run()
它将在另一个线程上调用一次。
So, if you have a TASK that needs to be on its own thread (disc IO, socket listening, etc), then you need a class to handle that task.
因此,如果您有一个需要在其自己的线程(磁盘 IO、套接字侦听等)上运行的 TASK,那么您需要一个类来处理该任务。
@ndpu's answer solves your scope/access problems.
@ndpu 的回答解决了您的范围/访问问题。