python3是如何使用线程的(Event与Condition)

创建线程

python3中使用threading来创建线程,代码如下:

from threading import Thread
t = Thread(target = myfunction,args=(function_arg1,...))
t.start()

使用target指定线程需要进行的操作,创建一个线程实例后,在调用start()方法之前,线程不会被执行。可以使用t.is_alive()查询线程是否在运行。

线程同步操作

Event

使用Event来对线程进行阻塞操作,Event对象有四个基本的方法,创建实例时flag被设置为false。

wait()	# 阻塞,直到flag被设置为true或者超时
set()		# 执行,将event内部的flag设置为true
clear()	# 清除标识位,重新设置为false
isSet()	# 判断flag是否为true

参看以下代码可以对基本的使用方法进行了解:

import time
from threading import Thread,Event

def countdown(n,started_evt):
	print('countdown starting')
	while n > 0:
		print('T-minus',n)
		if n == 7:
			started_evt.set()	# 第一次停止阻塞
		if n < 3 and started_evt.isSet() == False:
			started_evt.set()	# 第二次停止阻塞
		n -= 1
		time.sleep(2)

started_evt = Event()
t = Thread(target=countdown,args=(10,started_evt))
t.start()

started_evt.wait()	# 第一次阻塞
for i in range(20):
	print('main count :{}'.format(i))
	if i == 10:
		started_evt.clear()
		started_evt.wait()	# 再次阻塞

主线程阻塞

上述代码第19行中使用wait()方法第一次阻塞主线程,使其执行子线程中的代码直到第9行中停止阻塞。当主线程进入第22行中所写的条件后,使用clear()重置事件并使用wait()再次阻塞主线程,直到第11行再次停止阻塞。
这里值得注意的是,event阻塞的是wait()所在部分的线程,也就是说,如果wait()在函数countdown中使用,阻塞的将会是子线程。
示例代码以及输出结果如下:

import time
from threading import Thread,Event

def countdown(n,started_evt):
	print('countdown starting')
	while n > 0:
		print('T-minus',n)
		if n == 6:
			print('wait...')
			started_evt.wait()
		n -= 1
		time.sleep(2)

started_evt = Event()
t = Thread(target=countdown,args=(10,started_evt))
t.start()
print('get it !')

子线程阻塞
在python cookbook中建议event作为一次性事件使用 ,即一旦调用了set()方法,就弃用此event,因为多次使用clear()可能会因为程序员考虑上的疏忽造成线程混乱。如果线程打算重复通知某个时间,最好使用Condition对象来处理。

Condition

Condition可以进行多次通知,并通知不同数量的线程,基本的方法如下:

acquire()	#线程锁
release()	#释放锁
wait(timeout)	#线程挂起,直到收到notify
notify(n=1)		#通知至少一个线程
notify_all()	#通知所有线程

前面的两个锁相关方法在此不再赘述,也就是在运行时锁住线程使代码能够完整执行。这里主要说一下wait()notify()

import threading
import time

product = [0]
def consumer(cond):
    with cond:
        print('wait for product')
        cond.wait()
        print('get product:{}'.format(product))

def producer(cond):
    product.append(10)
    with cond: 
        cond.notify()	# 唤起一个
        print('notify !')
    time.sleep(3)
    product.append(20)
    with cond:
        cond.notify()	# 再唤起一个
        print('notify !')
    time.sleep(3)
    product.append(30)
    with cond:
        cond.notify_all()	# 全部唤起
        print('notify all!')

condition = threading.Condition()

c1 = threading.Thread(name='c1',target=consumer,args=(condition,))
c2 = threading.Thread(name='c2',target=consumer,args=(condition,))
c3 = threading.Thread(name='c3',target=consumer,args=(condition,))
c4 = threading.Thread(name='c4',target=consumer,args=(condition,))
p = threading.Thread(name='p',target=producer,args=(condition,))

c1.start()
c2.start()
c3.start()
c4.start()

p.start()

condition阻塞多线程
仔细看看代码就能看明白,消费者在等待生产,而在生产者多次notify的过程中,不断有消费者线程被唤起。

其它

除了上面的两种模式以外,还有一些其他的线程间通讯手段,比如actor等,这些以后有时间在补充。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值