<p>你不能直接做你想做的事。后台线程正在运行其<code>run</code>函数,该函数只是永远循环,因此它不可能执行任何其他操作。</p>
<p>当然,您可以在自己的线程上调用类的方法,但这可能不是您想要的。</p>
<hr/>
<p>Qt、.NET或Cocoa等框架可以提供<code>runOnOtherThread</code>类型方法的原因是每个线程都运行一个“事件循环”,所以它们真正做的就是发布一个事件。如果将<code>run</code>方法重写为一个事件循环,您可以自己完成这项工作。例如:</p>
<pre><code>import queue
import threading
class SomeClass(threading.Thread):
def __init__(self, q, loop_time = 1.0/60):
self.q = q
self.timeout = loop_time
super(SomeClass, self).__init__()
def onThread(self, function, *args, **kwargs):
self.q.put((function, args, kwargs))
def run(self):
while True:
try:
function, args, kwargs = self.q.get(timeout=self.timeout)
function(*args, **kwargs)
except queue.Empty:
self.idle()
def idle(self):
# put the code you would have put in the `run` loop here
def doSomething(self):
pass
def doSomethingElse(self):
pass
</code></pre>
<p>现在,您可以这样做:</p>
<pre><code>someClass = SomeClass()
someClass.start()
someClass.onThread(someClass.doSomething)
someClass.onThread(someClass.doSomethingElse)
someClass.onThread(someClass.doSomething)
</code></pre>
<p>如果希望稍微简化调用接口,以牺牲类中的更多代码为代价,可以添加如下包装方法:</p>
<pre><code> def _doSomething(self):
# put the real code here
def doSomething(self):
self.onThread(self._doSomething)
</code></pre>
<hr/>
<p>但是,除非您的<code>idle</code>方法有工作要做,否则您实际上只是在这里构建一个等效于单线程线程池的线程池,并且有比从头构建更简单的方法。例如,使用PyPI外的<a href="https://pypi.python.org/pypi/futures">^{<cd5>}</a>模块(Python 3<code>concurrent.futures</code>模块的后台端口):</p>
<pre><code>import futures
class SomeClass(object):
def doSomething(self):
pass
def doSomethingElse(self):
pass
someClass = SomeClass()
with futures.ThreadPoolExecutor(1) as executor:
executor.submit(someClass.doSomething)
executor.submit(someClass.doSomethingElse)
executor.submit(someClass.doSomething)
</code></pre>
<p>或者,只要stdlib:</p>
<pre><code>from multiprocessing import dummy as multithreading
class SomeClass(object):
def doSomething(self):
pass
def doSomethingElse(self):
pass
someClass = SomeClass()
pool = multithreading.Pool(1)
pool.apply(someClass.doSomething)
pool.apply(someClass.doSomethingElse)
pool.apply(someClass.doSomething)
pool.close()
pool.join()
</code></pre>
<p>池还有其他一些优势,执行者更是如此。例如,如果方法返回值,并且您希望启动两个函数,然后等待结果,然后启动前两个函数的结果的第三个函数,该怎么办?简单:</p>
<pre><code>with futures.ThreadPoolExecutor(1) as executor:
f1 = executor.submit(someClass.doSomething)
f2 = executor.submit(someClass.doSomethingElse)
futures.wait((f1, f2))
f3 = executor.submit(someClass.doSomethingElser, f1.result(), f2.result())
result = f3.result()
</code></pre>
<p>即使您稍后切换到4个线程池,因此<code>f1</code>和<code>f2</code>可能同时等待并且<code>f2</code>甚至可能首先返回,您也可以保证在这两个线程完成后立即启动<code>doSomethingElser</code>。</p>
<hr/>
<p>这里还有另一种可能性。您真的需要在该线程中运行代码吗,还是只需要它来修改线程所依赖的变量?如果是后者,只需同步对变量的访问。例如:</p>
<pre><code>class SomeClass(threading.Thread):
def __init__(self):
self.things_lock = threading.Lock()
self.things = []
while True:
with self.lock:
things = self.things[:]
for thing in things:
# pass
def doSomething(self):
with self.lock:
self.things.append(0)
someClass = SomeClass()
someClass.start()
someClass.doSomething()
</code></pre>
<p>站在这条主线上没有什么神奇的。如果除了需要修改<code>SomeClass</code>所依赖的变量之外,您还希望将<code>doSomething</code>从主线程中踢出,这样您就可以做比等待它完成更重要的事情,那么您可以创建一个短期的额外线程来<code>doSomething</code>:</p>
<pre><code>someClass = SomeClass()
someClass.start()
somethingThread = threading.Thread(target=someClass.doSomething)
somethingThread.start()
doOtherImportantStuffWithSomethingIsHappening()
somethingThread.join()
</code></pre>