python多线程编程第二篇

threading 模块

       threading 模块是python多线程编程提供的更高级别的模块,它不仅提供了 Thread 类,还提供了各种非常好用的同步机制,下表列出了 threading 模块里所有的对象。

threading 模块对象说明
Thread表示一个线程的执行的对象
Lock锁原语对象(跟 thread 模块里的锁对象相同)
RLock可重入锁对象。使单线程可以再次获得已经获得了的锁(递归锁定)。
Condition条件变量对象能让一个线程停下来, 等待其它线程满足了某个“条件”。如,状态的改变或值的改变。
Event通用的条件变量。多个线程可以等待某个事件的发生,在事件发生后,所有的线程都会被激活。
Semaphore为等待锁的线程提供一个类似“等候室”的结构
BoundedSemaphore与 Semaphore 类似,只是它不允许超过初始值
Timer与 Thread 相似,只是,它要等待一段时间后才开始运行。

除了各种同步对象和线程对象外,threading 模块还提供了下列函数:

threading 模块函数说明
activeCount()当前活动的线程对象的数量
currentThread()返回当前线程对象
enumerate()返回当前活动线程的列表
settrace(func)为所有线程设置一个跟踪函数
setprofile(func)为所有线程设置一个 profile 函数

Thread 类

       threading 的 Thread 类是你主要的运行对象。它有很多 thread 模块里没有的函数,详见下表:

函数说明
start()开始线程的执行
run()定义线程的功能的函数(一般会被子类重写)
join(timeout=None)程序挂起,直到线程结束;如果给了 timeout,则最多阻塞 timeout 秒
getName()返回线程的名字
setName(name)设置线程的名字
isAlive()布尔标志,表示这个线程是否还在运行中
isDaemon()返回线程的 daemon 标志
setDaemon(daemonic)把线程的 daemon 标志设为 daemonic (一定要在调用 start()函数前调用)



使用 Thread 类,可以有多种方法来创建线程。这里介绍三种方法,下面我们将用这三种方法分别重写之前的例子。

创建一个 Thread 的实例,传给它一个函数

#!/usr/bin/env python

import threading
from time import sleep, ctime

loops = [ 4, 2 ]

def loop(nloop, nsec):
    print('start loop', nloop, 'at:', ctime())
    sleep(nsec)
    print('loop', nloop, 'done at:', ctime())

def main():
    print('starting at:', 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:            # start threads
        threads[i].start()

    for i in nloops:            # wait for all
        threads[i].join()       # threads to finish

    print('all DONE at:', ctime())

if __name__ == '__main__':
    main()

运行结果:

starting at: Tue Aug 22 21:36:09 2017
start loop 0 at: Tue Aug 22 21:36:09 2017
start loop 1 at: Tue Aug 22 21:36:09 2017
loop 1 done at: Tue Aug 22 21:36:11 2017
loop 0 done at: Tue Aug 22 21:36:13 2017
all DONE at: Tue Aug 22 21:36:13 2017

在实例化每个 Thread 对象的时候, 我们把函数(target) 和参数(args) 传进去, 得到返回的 Thread实例。实例化一个 Thread(调用Thread())与调用 thread.start_new_thread()之间最大的区别就是,新的线程不会立即开始。在你创建线程对象,但不想马上开始运行线程的时候,这是一个很有用的同步特性。所有的线程都创建了之后,再一起调用 start()函数启动,而不是创建一个启动一个。而且不用再管理一堆锁(分配锁, 获得锁, 释放锁, 检查锁的状态等), 只要简单地对每个线程调用 join()函数就可以了。join()会等到线程结束,或者在指定timeout 参数的时候,等到超时为止。join()的另一个比较重要的方面是它可以完全不用调用。一旦线程启动后,就会一直运行,直到线程的函数结束,退出为止。如果你的主线程除了等线程结束外,还有其它的事情要做(如处理或等待其它的客户请求), 那就不用调用 join(), 只有在你要等待线程结束的时候调用 join()即可。

创建一个 Thread 的实例,传给它一个可调用的类对象

与传一个函数很相似的另一个方法是在创建线程的时候,传一个可调用的类的实例供线程启动的时候执行——这是多线程编程的一个更为面向对象的方法。相对于一个或几个函数来说,由于类对象里可以使用类的强大的功能,可以保存更多的信息,这种方法更为灵活。

#!/usr/bin/env python

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.func(*self.args)

def loop(nloop, nsec):
    print('start loop', nloop, 'at:', ctime())
    sleep(nsec)
    print('loop', nloop, 'done at:', ctime())

def main():
    print('starting at:', ctime())
    threads = []
    nloops = range(len(loops))

    for i in nloops:    # create all threads
        t = threading.Thread(
        target=ThreadFunc(loop, (i, loops[i]),
        name=loop.__name__))
        threads.append(t)

    for i in nloops:    # start all threads
        threads[i].start()

    for i in nloops:    # wait for completion
        threads[i].join()

    print('all DONE at:', ctime())

if __name__ == '__main__':
    main()

运行结果:

starting at: Tue Aug 22 22:09:04 2017
start loop 0 at: Tue Aug 22 22:09:04 2017
start loop 1 at: Tue Aug 22 22:09:04 2017
loop 1 done at: Tue Aug 22 22:09:06 2017
loop 0 done at: Tue Aug 22 22:09:08 2017
all DONE at: Tue Aug 22 22:09:08 2017

这次又改了些什么呢?主要是增加了 ThreadFunc 类和创建 Thread 对象时会实例化一个可调用类 ThreadFunc 的类对象。也就是说,我们实例化了两个对象。下面,来仔细地看一看 ThreadFunc类吧。我们想让这个类在调用什么函数方面尽量地通用,并不局限于那个 loop()函数。所以,我们加了一些修改,如,这个类保存了函数的参数,函数本身以及函数的名字字符串。构造函数init()里做了这些值的赋值工作。创建新线程的时候, Thread 对象会调用我们的 ThreadFunc 对象, 这时会用到一个特殊函数call()。

从 Thread 派生出一个子类,创建一个这个子类的实例

#!/usr/bin/env python

import threading
from time import sleep, ctime

loops = [ 4, 2 ]

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):
        self.func(*self.args)

def loop(nloop, nsec):
    print('start loop', nloop, 'at:', ctime())
    sleep(nsec)
    print('loop', nloop, 'done at:', ctime())

def main():
    print('starting at:', 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:', ctime())

if __name__ == '__main__':
    main()

运行结果:

starting at: Tue Aug 22 22:08:03 2017
start loop 0 at: Tue Aug 22 22:08:03 2017
start loop 1 at: Tue Aug 22 22:08:03 2017
loop 1 done at: Tue Aug 22 22:08:05 2017
loop 0 done at: Tue Aug 22 22:08:07 2017
all DONE at: Tue Aug 22 22:08:07 2017

一般来说,从面向对象的角度讲,建议使用第三种方法,第三种方法扩展性更好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值