Fork me on GitHub

python-多线程


python中有关多线程的操作方法。

threading库是python支持多线程编程的重要模块。

线程的创建

一种方法是直接使用threading中的Thread类创建对象。

另一种方法是继承Thread类并重写__init__()run()方法。

线程的管理

join([timeout])

阻塞当前线程,等待被调线程结束或超时后再执行当前线程,timeout单位是秒。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from threading import Thread
import time
def fun(x, y):
for i in range(x, y):
print(i, end=' ')
print()
time.sleep(10) #等待10秒
t1 = Thread(target=fun, args=(15, 20))
t1.start()
t1.join(5) #等待t1结束或等待5秒
t2 = Thread(target=fun, args=(5, 10))
t2.start()

isAlive()

测试线程是否处于运行状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from threading import Thread
import time
def fun():
time.sleep(10) #等待10秒
t1 = Thread(target=fun)
print('t1:',t1.isAlive()) #False
t1.start()
print('t1:',t1.isAlive()) #True
t1.join(5) #因超时而结束
print('t1:',t1.isAlive()) #True
t1.join() #等待t1结束
print('t1:',t1.isAlive()) #False

daemon属性

如某个子线程的daemon属性为False(默认情况),主线程结束时会检测该子线程是否结束并等待它结束后再退出。若为True,则该子线程不管有没有运行玩,都会随主线程一起结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import threading
import time
class mythread(threading.Thread):
def __init__(self, num, threadname):
threading.Thread.__init__(self,name=threadname)
self.num = num
def run(self):
time.sleep(self.num)
print(self.num)
t1 = mythread(1, 't1')
t2 = mythread(5, 't2')
t2.daemon = True
t2.setDaemon(False)
print(t1.daemon) #False
print(t2.daemon) #True
t1.start()
t2.start()

1会输出,但5不会输出。

线程的同步

RLock对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import threading
import time
class mythread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global x
lock.acquire() #获取锁,如果成功则进入临界区
x += 1
time.sleep(0.5)
print(x)
lock.release() #释放锁,退出临界区
lock = threading.RLock()
tl = [] #用来存放多个进程
x = 0
for i in range(10000):
t = mythread()
tl.append(t)
for i in tl:
i.start()

如果没有这把读锁,那么x的值将会变得杂乱无章,出现“脏读”现象。

“死锁”现象:假设有两个线程和两把锁,只有两把锁都给同一个线程的时候这个线程才会运行。那么问题来了,当两个线程各自获得了其中的一把锁,这时它们都在等待另一把锁释放,这时就会出现死锁现象。

Condition对象

用经典的生产者和消费者问题演示。

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
import threading
from random import randint
import time
class Producer(threading.Thread):
def __init__(self, threadname):
threading.Thread.__init__(self,name=threadname)
def run(self):
global x
while True:
con.acquire() #获取锁
if len(x) == 10:
print('Producer is waiting')
con.wait() #共享列表已有10个元素,不再生产
else:
print('Producer:', end=' ')
x.append(randint(1,1000))
print(x)
time.sleep(1)
con.notify() #唤醒等待条件的线程
con.release() #释放锁
class Consumer(threading.Thread):
def __init__(self, threadname):
threading.Thread.__init__(self, name =threadname)
def run(self):
global x
while True:
con.acquire()
if not x:
print('Consumer is waiting')
con.wait() #共享列表没东西,暂停消费
else:
print(x.pop(0))
print(x)
time.sleep(1)
con.notify()
con.release()
con = threading.Condition()
x = []
p = Producer('Producer')
c = Consumer('Consumer')
p.start()
c.start()
p.join()
c.join()

notify()方法是从所有等待这个对象锁的线程中随机唤醒一个。

notify_all()方法能够唤醒所有正在等待这个对象锁的线程,唤醒的线程获得锁的概率是随机的,取决于cpu调度。

notify()或者notify_alll()方法并不是真正释放锁,必须等到release方法执行完才真正释放锁。

donate the author