多线程,任何语言都绕不过的一道弯儿,在这里就走一遭吧。
python版本3.1
python对于多线程的实现,主要依靠模块threading和thread。其中threading是一个高层模块,对较为底层的thread进行了一些必要的封装。
下面来看看threading模块中的几个方法吧。
threading.active_count() 返回当前处于alive状态的Thread对象的个数。
threading.current_thread() 返回当前Thread对象。
threading.enumerate() 返回当前处于alive状态的Thread对象的集合。
Thread 对象
这是python多线程机制的核心类。每个线程都是Thread对象。
下面对其方法作一下介绍。
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})
在使用该构造函数时,参数的设置必须显式地进行。
group 默认为None,预留的扩展参数以应对ThreadGroup类的实现。
target 一个被run()方法调用的可运行的对象,方法也是对象哦。默认为None,也就是run不做任何操作。
name 线程名称。默认情况下,会被构造函数创建一个"Thread-N"的名称,N
是一个小的数字。
args 是target指向的运行对象的参数元组。默认是()。
kwargs 是target指向的运行对象的字典参数。默认为{},其功能与args是一致的。
如果子类想继承Thread类,必须首先执行Thread.__init__()方法。
start()
激活线程。它做的事情其实就是调用该线程对象的run()方法。
run()
运行线程。如果采用继承的方式来创建多线程,必须重写此方法。
join(timeout=None)
等待直到该线程终结。该方法会使得调用该线程的调用者处于等待状态,直到该线程运行完。
如果timeout参数被设置,则表示在timeout秒内,如果该线程依然未终结,则调用者也会执行下面的逻辑。这个时候,可以使用is_alive()方法来判断该线程是否执行完毕。
name
线程名,在多线程中,该属性的值并不唯一。
ident
用来标识一个线程。在该线程start之前,该属性的值为None,线程开始之后会被赋值,即使在线程结束之后,该值依然有效。
is_alive()
判断线程是否alive。alive状态是指线程start()执行之后而run()方法未执行完之前的状态。daemon
布尔值。True表示为守护线程。该线程的设置必须在start()之前。初始值从你线程继承而来,主线程为非daemon线程。
对于共享数据的同步问题,我们选两个比较常用的方法来解决。
RLock对象
该对象可对共享数据进行重复加锁和解锁,只要配对就可以了。
使用方法也很简单,acquire()方法和release()方法之间的就是临界区,在临界区内操作共享数据就是了。
RLock.acquire(blocking=True)
当blocking设置为true时,在加锁状态,其它线程A想获得锁,则A线程会被阻塞,直到解锁返回为True。
当blocking设置为true时,在加锁状态,其它线程A想获得锁,则A线程不会被阻塞,直接返回False。
RLock.release()
解锁,无返回值。
Condition对象
个人认为Condition对象,是对Lock对象的一种再封装。你可以传给它一个已有的锁对象,如果未指定,则自行创建一个锁。
threading.Condition(lock=None)
默认为None,可传给它一个Lock或者RLock对象。
acquire(*args)
获得潜在的锁。说白了,就是调用潜在锁对象的acquire()方法,人家返回啥,它也就返回啥了。
release()
释放潜在锁,没有返回值。
wait(timeout=None)
等待直到被唤醒或者timeout时间到。如果调用者并未获得锁而执行此方法,则会抛出RuntimeError异常。
这个方法会释放锁,然后睡眠直到在其它线程被同一condition变量的notify()或者notify_all()方法唤醒,或者timeout时间到。如果被唤醒,它将重新获得锁。
notify()
唤醒在这个condition对象上睡眠的一个线程,如果有的话。如果没有获得锁而调用此方法,则会抛出RuntimeError异常。
该方法会唤醒一个线程,如果没有线程在睡眠,该方法不做其它操作。
记住:notify()方法并没有释放锁,所以,还得你自己亲力亲为哦。
notify_all()
方法与notify()类似,不过是唤醒所有睡眠线程。
Event对象
这个对象用来进行进程间的简单通信。上面的Condition对象来RLock对象用来对共享数据进行操作,当然,在一定程度上,也实现了线程间的通信。但二者的侧重点是不一样的。Event并没有涉及共享数据的操作。
class threading.Event
is_set()
返回为True如果内部标志已经被设置为True的话。
set()
设置内部标志为True。线程在内部标志为true时才会被唤醒。如果内部标志被设置为true,又调用wait()方法,则不会睡眠。
clear()
设置内部标志为false。
wait(timeout=None)
在内部标志为false时,进入睡眠状态,直到该标志被设置为true时才会被唤醒。
Timer对象
周期性执行某任务的类。直接以例子来说话吧。
def hello():
print("hello, s")
obj = Timer(30.0, hello)
t.start()
#t.cancel()