在python中,启用线程有两种方式,一种是利用_thread模块,另一种是用threading模块。一般来说,不建议直接使用_thread模块。但是某些简单的场合也是可以使用的,因为_thread模块的使用方法非常非常的简单。
_thread模块的核心是_thread.start_new_thread方法
_thread.start_new_thread(function, args, [,kwargs])
启动一个新线程并返回其标识符,线程使用args作为执行函数。这个args必须是元组。可选kwargs参数指定关键字参数的字典。当函数返回时,线程将以静默方式退出。当函数以未处理的异常终止时,将打印堆栈跟踪,然后线程退出(其他线程继续运行)
举个例子
import time
import datetime
import _thread
date_time_format = '%H:%M:%S'
def get_time_str():
now = datetime.datetime.now()
return datetime.datetime.strftime(now, date_time_format)
def thread_function(thread_id):
print('Thread %d\t start at %s' % (thread_id, get_time_str()))
print('Thread %d\t sleeping' % thread_id)
time.sleep(4)
if thread_id==3:
raise Exception('xxx')
print('Thread %d\t finish at %s' % (thread_id, get_time_str()))
def main():
print('Main thread start at %s' % get_time_str())
for i in range(5):
_thread.start_new_thread(thread_function, (i, ))
time.sleep(1)
time.sleep(6)
print('Main thread finish at %s' % get_time_str())
if __name__ == '__main__':
main()
从代码之中我们可以看到,我在thread_id==3时,抛出一个异常。这时候,第三个线程就自动终止了,并且会在屏幕上打印异常信息。
从执行结果可以看出,_thread模块的start_new_thread方法提供了一种比较简单的多线程机制。单个线程在执行时,别的线程也在“同步”地被执行。虽然从上面的执行结果可以看出执行结果是“顺序”的,但是,也肯出现两行结果相重叠的情况。不信可以试试删掉那个sleep(1)。这是因为线程之间的调度是很难预知的。
那么,我们为什么要在主线程之中加sleep(6)呢?这个目的是为了让主线程不要执行完就立即退出。主线程一旦结束,其他线程无论是否执行完,都会强制退出。
但是,问题来了。
我们在真实情况下,怎么知道线程会在什么时候结束呢?主线程过早或者过晚退出都不是我们所希望的。这时候我们就需要用到线程锁,主线程可以在其他线程执行完之后立即退出。
_thread.allocate_lock方法返回一个Lock对象。Lock对象有三个常见的方法:acquire,release,locked
acquire方法用来获取一个线程锁。release方法用来释放线程锁。locked方法用于获取一个Lock对象是否被锁定。
来举个例子吧,还是参照上面那个例子,做一点点改进。
import time
import datetime
import _thread
date_time_format = '%H:%M:%S'
def get_time_str():
now = datetime.datetime.now()
return datetime.datetime.strftime(now, date_time_format)
def thread_function(thread_id, lock):
print('Thread %d\t start at %s' % (thread_id, get_time_str()))
print('Thread %d\t sleeping' % thread_id)
time.sleep(4)
print('Thread %d\t finish at %s' % (thread_id, get_time_str()))
lock.release()
def main():
print('Main thread start at %s' % get_time_str())
locks = []
for i in range(5):
lock = _thread.allocate_lock()
lock.acquire()
locks.append(lock)
for i in range(5):
_thread.start_new_thread(thread_function, (i, locks[i]))
time.sleep(1)
for i in range(5):
while locks[i].locked():
time.sleep(1)
print('Main thread finish at %s' % get_time_str())
if __name__ == '__main__':
main()
从运行的结果可以看出,使用线程锁可以避免主线程过早或过晚退出而产生不可预期的结果。