之前提了Python多线程的一点使用,今天介绍更好的threading模块,它提供了Thread类和一些比较好用的同步机制。
先介绍Thread类
threading模块中的Thread类有很多thread模块里没有的方法,一般使用时可以选择几种方法里的一种:
- 创建一个Thread实例,传给它一个函数;
- 创建一个Thread实例,传给它一个可调用的类对象;
- 从Thread派生一个子类,创建这个子类的实例。
可以看看它有哪些方法
函数 | 描述 |
start() | 开始线程的执行 |
run() |
定义线程的功能的函数(一般会被子类重写) |
join(timeout=None) | 程序挂起,知道线程结束,如果给了timeout,最多阻塞timeout秒 |
getName() |
返回线程的名字 |
setName(name) | 设置线程的名字 |
isAlive() | 布尔标志,表示这个线程是否还在运行中 |
isDaemon() | 返回线程的daemon标志 |
setDaemon(daemonic) | 把线程的daemon标志设置成daemonic |
用threading模块重写我们上次的例子:
import threading from time import sleep, ctime loops = [4, 2] def loop(nloop, nsec): print 'start loop%s at: %s ' % (nloop, ctime()), sleep(nsec) print 'loop%s done at: %s ' % (nloop, ctime()), def main(): print 'starting at: %s ' % ctime(), threads = [] nloops = range(len(loops)) for i in nloops: t = threading.Thread(target = loop, args=(i,loops[i])) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() print 'all DONE at: %s ' %ctime(), if __name__ == '__main__': main()
结果也是如下显示:
>>> starting at: Sun Jan 03 11:37:43 2016 start loop0 at: Sun Jan 03 11:37:43 2016 start loop1 at: Sun Jan 03 11:37:43 2016 loop1 done at: Sun Jan 03 11:37:45 2016 loop0 done at: Sun Jan 03 11:37:47 2016 all DONE at: Sun Jan 03 11:37:47 2016
比起昨天的锁,这里只需要简单地对每个线程使用join()函数就可以了。
join()看上去会比一个等待锁释放的无限循环清楚一些。它另一个很重要的方面是可以完全不用调用,一旦线程启动后就会一直执行,知道线程的函数结束退出位置。
上面使用的是一种传递函数给Thread模块,也可以在创建线程的时候,传一个可调用的类的实例来供线程启动的时候执行,这是一种更面为对象的方法。
代码如下:
import threading from time import sleep, ctime loops = [4, 2] class ThreadFunc(object): def __init__(self, func, args, name=''): self.name = name self.func = func self.args = args def __call__(self): self.res = self.func(*self.args) def loop(nloop, nsec): print 'start loop %s at: %s ' %(nloop, ctime()), sleep(nsec) print 'loop %s done at: %s ' %(nloop, ctime()), def main(): print 'starting at:', ctime() threads = [] nloops = range(len(loops)) for i in nloops: t = threading.Thread( target = ThreadFunc(loop, (i,loops[i]), loop.__name__)) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() print 'all DONE at:', ctime() if __name__ == '__main__': main()
结果和上面是一样的,这里就不贴了。
可以看到我们怎家了一个ThreadFunc类和创建Thread对象时实例化一个可调用类ThreadFunc的类对象。
创建线程时,Thread对象会调用我们的ThreadFunc对象,会用到一个特殊函数__call__(),由于我们已经有了要用的参数,所以不再传到Thread()构造器中。
最后一种方法是从Thread类中派生一个子类,然后创造这个子类的实例。
import threading from time import sleep, ctime loops = [2, 4] class MyThread(threading.Thread): def __init__(self, func, args, name=''): threading.Thread.__init__(self) self.name = name self.func = func self.args = args def run(self): apply(self.func, self.args) def loop(nloop, nsec): print 'start loop%s at: %s' %(nloop, ctime()) sleep(nsec) print 'loop%s done at:%s' %(nloop, ctime()) def main(): print 'starting at:%s' % ctime() threads = [] nloops = range(len(loops)) for i in nloops: t = MyThread(loop, (i, loops[i]), loop.__name__) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() print 'all DONE at: %s' % ctime() if __name__ == '__main__': main()