Python 多线程技巧 用threading.Event代替time.sleep()
果我们碰到了这样的场景:线程1做一件时间较长的事情,等做完了,主程序去测试其状态是不是真的更改了。
通常比较容易想到的是:
-
线程1里,用大循环来模拟这个长时间的函数,比如for i in range(1, 10000)等等;
-
主程序里,用比如time.sleep(60)去等待,默许60秒应该已经够线程1去run了。
显然,这样做是不严谨的,因为没办法确切控制线程1的时间,所以测试程序可能会fail掉。
好的解决办法是用threading.Event的wait()和set()来精确控制线程。
见代码如下:
线程1:Work
主线程:跟踪测试is_done的状态。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import threading
def DoWork(work, callback):
def Task():
print 'work begin...'
work()
print 'work done!'
print 'callback begin...'
callback()
print 'callback done!'
t = threading.Thread(target=Task)
t.start()
def TestWorkAndDone():
is_started = threading.Event()
can_done = threading.Event()
is_done = threading.Event()
def Work():
"""it's not a good idea to use huge for loop here to kill time,
because the start and end time are not under the control.
"""
print '1'
is_started.set()
print '2'
# block here until can_done.set() is called.
can_done.wait(timeout=60) # .await() in Java
print '7'
DoWork(work=Work, callback=lambda:is_done.set())
print '3'
# block here until is_started.set() is called.
is_started.wait(timeout=60)
print '4'
if is_started.isSet():
print 'SUCCESS: Work started'
if is_done.isSet():
print 'FAILD: Work hasnot done'
print '5'
can_done.set() # Work() is unblock.
print '6'
# block here until callback() is called.
# no need to use time.sleep(60) here.
is_done.wait(timeout=60)
if is_done.isSet():
print '<mce:script type="text/javascript" src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js" mce_src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js"></mce:script><mce:script type="text/javascript" src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js" mce_src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js"></mce:script>SUCCESS: Work done'
# main
TestWorkAndDone()