在Python中创建线程

25 投票
4 回答
64950 浏览
提问于 2025-04-15 22:59

我有一系列的“任务”,想要在不同的线程中运行。这些任务是由不同的模块来完成的,每个模块都包含处理其任务的业务逻辑。

给定一组任务,我希望能够为每个模块启动一个新的线程,如下所示。

from foobar import alice, bob charles
data = getWorkData()
# these are enums (which I just found Python doesn't support natively) :(
tasks = (alice, bob, charles)

for task in tasks
  # Ok, just found out Python doesn't have a switch - @#$%!
  # yet another thing I'll need help with then ...
  switch
    case alice:
      #spawn thread here - how ?
      alice.spawnWorker(data)

显然,我还是在用C++的思维方式。请问我该如何用Python的方式,利用Python的“枚举”和“开关”,来在新线程中运行一个模块呢?

显然,这些模块都会有一个类,它是从一个叫做Plugin的抽象基类(ABC)派生出来的。spawnWorker()方法会在Plugin接口中声明,并在各个模块实现的类中定义。

也许,还有更好的(也就是更符合Python风格的)做法?我很想知道。

[编辑]

我刚刚多读了一些,似乎Python并没有真正意义上的线程实现(至少不是C++程序员所理解的那种)。不过,这对我来说并不是问题。每个任务都比较耗时,我不想等一个任务完成后再开始另一个,这就是我使用线程的原因。时间片调度对我来说没什么影响——只要它们几乎同时(或者紧接着)启动,Python就可以在这些线程之间随意进行时间片调度——这对我来说没问题。

我在这里看到过一个类似问题的回答。

有用户提供了一个简单的线程类,如下所示:

import threading
class Foo (threading.Thread):
    def __init__(self,x):
        self.__x = x
        threading.Thread.__init__(self)
    def run (self):
          print str(self.__x)

for x in xrange(20):
    Foo(x).start()

我在考虑将这个用于我的ABC Plugin。那么我的问题是,实际任务的代码应该放在哪里(也就是业务逻辑)?我假设这应该放在Foo类的run()方法中(这个问题很明显,我知道,但我不想做任何假设)。

我的想法是对的还是有问题(如果有问题,我错过了什么)?

4 个回答

4

顺序执行:

from foobar import alice, bob, charles

for fct in (alice, bob, charles):
    fct()

并行执行:

from threading import Thread
from foobar import alice, bob, charles

for fct in (alice, bob, charles):
    Thread(target=fct).start()
5
import threading
from foobar import alice, bob, charles

data = get_work_data() # names_in_pep8 are more Pythonic than camelCased

for mod in [alice, bob, charles]:
    # mod is an object that represent a module
    worker = getattr(mod, 'do_work')
    # worker now is a reference to the function like alice.do_work
    t = threading.Thread(target=worker, args=[data])
    # uncomment following line if you don't want to block the program
    # until thread finishes on termination
    #t.daemon = True 
    t.start()

把你的逻辑放在对应模块的 do_work 函数里。

42

与其使用 switch-case 这种方式,不如用更合适的多态性来处理问题。比如,在 Python 中,你可以利用鸭子类型来做到这一点:

在,比如说,alice.py 文件中:

def do_stuff(data):
    print 'alice does stuff with %s' % data

在,比如说,bob.py 文件中:

def do_stuff(data):
    print 'bob does stuff with %s' % data

然后在你的主程序代码中,比如说,main.py 文件:

import threading
import alice, bob

def get_work_data():
    return 'data'

def main():
    tasks = [alice.do_stuff, bob.do_stuff]
    data = get_work_data()
    for task in tasks:
        t = threading.Thread(target=task, args=(data,))
        t.start()

如果需要我进一步解释,请告诉我。

撰写回答