在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()

从运行的结果可以看出,使用线程锁可以避免主线程过早或过晚退出而产生不可预期的结果。

你也可能喜欢

发表评论