Python线程学习

Python2.7中有两个常用的多线程库Multiprocessing,Threading。在Python中,线程和进程的区别在于线程模块使用线程,进程模块使用进程233,不开玩笑,这是StackOverFlow上的解释。说重点,线程使用相同的内存空间,而进程使用不同的。这也就让进程之间传对象稍有点困难。当然,由于线程共享内存空间,那么必须要考虑线程安全。

thread

thread算是轻量级的线程模块,它提供较为底层的多线程实现方案。使用start_new_thread(function, args[, kwargs])实现线程。使用allocate_lock()可以得到一个锁对象,用acquire()和release()来加锁和释放锁,用locked()来判断释放有锁。一把锁只能被一个线程得到,所以利用锁可以避免多个线程对同一资源的同时操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import thread
from time import sleep

def addLock(lock):
lock.acquire() # 获得锁
print lock.locked() # 判断是否有锁
sleep(1)
lock.release() # 释放锁

def main():
lock = thread.allocate() # 分配一个锁对象
thread.start_new(addLock,(lock,)) # 开辟一个线程
thread.start_new(addLock,(lock,))
sleep(3)

if __name__ == '__main__':
main()

threading

threading作为一个更高级的模块,提供了一些thread没有的功能。threading中有两种锁,如threading.Lock(), threading.RLock()。

Lock

这里lock和thread模块里类似。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import threading

def addLock(lock):
print lock.acquire(False)
# lock.release()

def main():
lock = threading.Lock()
t1 = threading.Thread(target=addLock, args=(lock,))
t2 = threading.Thread(target=addLock, args=(lock,))
t1.run()
t2.run()


if __name__ == '__main__':
main()

以上代码演示了利用Threading模块来确定一把锁只能被获得一次。

RLock

RLock是可重入锁(reentrant lock),acquire()能够不被阻塞的被同一个线程调用多次。要注意的是release()需要调用与acquire()相同的次数才能释放锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import threading,time

rlock=threading.RLock()
result=[]

def step1():
global result
if rlock.acquire():
result.append('step1')
time.sleep(0)
rlock.release()
def step2():
global result
if rlock.acquire():
result.append('step2')
time.sleep(0)
rlock.release()

def showresult():
print threading.current_thread() # 查看当前线程
if rlock.acquire():
step1()
step2()
rlock.release()
print result

def clearresult():
global result
if rlock.acquire():
result=None
time.sleep(1)
rlock.release()
print threading.current_thread()
print result

t1=threading.Thread(target=showresult)
t2=threading.Thread(target=clearresult)

t1.start()
t2.start()

Condition

条件同步机制是指:一个线程等待特定条件,而另一个线程发出特定条件满足的信号。 解释条件同步机制的一个很好的例子就是生产者/消费者(producer/consumer)模型。

Semaphore

信号量同步基于内部计数器,每调用一次acquire(),计数器减1;每调用一次release(),计数器加1.当计数器为0时,acquire()调用被阻塞。

Event

基于事件的同步是指:一个线程发送/传递事件,另外的线程等待事件的触发。在set()时, 其他线程就被唤醒执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# coding=utf-8

import threading, time
import random

class Producer(threading.Thread):
"""
向列表中生产随机整数
"""

def __init__(self, integers, event):
"""
构造器

@param integers 整数列表
@param event 事件同步对象
"""
threading.Thread.__init__(self)
self.integers = integers
self.event = event

def run(self):
"""
实现Thread的run方法。在随机时间向列表中添加一个随机整数
"""
while True:
integer = random.randint(0, 256)
self.integers.append(integer)
print '%d appended to list by %s' % (integer, self.name)
print 'event set by %s' % self.name
self.event.set() #设置事件
self.event.clear() #发送事件
print 'event cleared by %s' % self.name
time.sleep(1)

class Consumer(threading.Thread):
"""
从列表中消费整数
"""

def __init__(self, integers, event):
"""
构造器

@param integers 整数列表
@param event 事件同步对象
"""
threading.Thread.__init__(self)
self.integers = integers
self.event = event

def run(self):
"""
实现Thread的run()方法,从列表中消费整数
"""
while True:
self.event.wait() #等待事件被触发
try:
integer = self.integers.pop()
print '%d popped from list by %s' % (integer, self.name)
except IndexError:
# catch pop on empty list
time.sleep(1)

def main():
integers = []
event = threading.Event()
t1 = Producer(integers, event)
t2 = Consumer(integers, event)
t1.start()
t2.start()
t1.join()
t2.join()

if __name__ == '__main__':
main()