16.3. thread多线程控制

Note

thread模块在python3中更名为 _thread 当升级你的python源码到python3时,2to3工具会自动更换为import _thread ;然而,你应该考虑使用更高层次的线程模块threading

这个模块为多线程提供了一个底层 、原始的操作 (也可以成为light-weight processes 或者 tasks) — 多个控制线程共享全局数据空间。为了多线程同步,提供了简单的锁(也称呼为 mutexes 后者 binary semaphores) 。当然, threading 模块在thread模块之上提供了一个更容易使用、更高层次的线程API。

thread模块是可选的。它支持在Windows,linux,SGI IRIX,Solaris 2.x,以及有POSIX线程(也称为:pthread)的系统上运行。对于某些缺乏 thread 模块的操作系统,dummy_thread 模块可以作为一种替代。dummy_thread模块提供了和thread模块同样的接口,可以在使用中直接替换。

thread模块定义了下面的常量和函数:

exception thread.error

抛出thread-specific 异常错误。

thread.LockType

锁对象的类型。

thread.start_new_thread(function, args[, kwargs])

开启一个新的线程并返回线程的标识符。线程调用回调函数 function ,传递参数列表 args (这个列表必须是一个元祖)。 kwargs 参数选项指定了键值对字典参数。当回调函数执行完毕并返回时,线程会默认退出。当线程回调函数因未处理的异常而终止时,打印栈跟踪信息,之后线程退出(此时其他线程继续运行)。

thread.interrupt_main()

在主线程中抛出异常 KeyboardInterrupt非main线程可以使用该函数中断main线程。

New in version 2.3.

thread.exit()

抛出 SystemExit 异常。 如果没有捕获该异常,默认导致线程退出。

thread.allocate_lock()

返回一个新的锁对象。锁对象的相关方法在下面章节介绍。返回的锁对象初始化为未加锁状态。

thread.get_ident()

在当前线程中获取 ‘线程标识符’(译者注:该值等于主线程调用start_new_thread返回的值) 。 这是一个非0整数值。这个值不能直观的标识线程的信息。它旨在作为一个魔术cookie使用,例如索引一个线程特定数据的字典。当一个线程退出而另外一个线程刚好在此时创建,则线程标识符可能被循环利用。

thread.stack_size([size])

返回在线程创建时使用的stack size。size 选项参数用于设置之后创建线程时stack size值,0(平台或者配置默认值)或者一个大于32,768(32KB)的正数。如果修改为不支持的stack size值,就会抛出error 异常。如果指定的size参数是无效的, 抛出异常ValueError并且不修改stack size值。 32kB是当前最小的stack size值用以确保python解释器自身有足够的栈空间。 Note that some platforms may have particular restrictions on values for the stack size, such as requiring a minimum stack size > 32kB or requiring allocation in multiples of the system memory page size - platform documentation should be referred to for more information (4kB pages are common; using multiples of 4096 for the stack size is the suggested approach in the absence of more specific information). Availability: Windows, systems with POSIX threads.

New in version 2.5.

Lock对象的一些方法如下:

lock.acquire([waitflag])

如果没有选项参数,该方法会无条件的请求获取锁资源,阻塞等待直到其他线程释放锁(任何一个实现只能有一个线程拥有锁——这是它存在的意义)。如果 waitflag 参数存在,根据它的值有不同的动作:如果为0,非阻塞请求锁,如果不为0,方式同没有waitflag参数一样(译者注:不是超时?)。方法返回值为True表示成功获取锁, False 表示失败。

lock.release()

释放锁。必须是已经获得的锁,但可以不是同一个线程。

lock.locked()

返回锁的状态: True 表示已经有其他线程拥有该锁, False 则相反。

除了上述的方法,lock对象也被用于 with 语句,例如:

import thread

a_lock = thread.allocate_lock()

with a_lock:
    print "a_lock is locked while this executes"

注意事项:

  • Threads和中断的交互非常奇怪: KeyboardInterrupt 可以被任意一个线程接收。(当 signal模块被使用时,中断信号总是发往主线程。)

  • 调用 sys.exit() 或者抛出 SystemExit 异常的效果等同于 thread.exit()

  • acquire()不可中断— KeyboardInterrupt 异常信号会在获取锁之后被捕获或者响应。

  • 当主线程退出时,其他线程的行为是平台定义的。On SGI IRIX using the native thread implementation, they survive. On most other systems, they are killed without executing try ... finally clauses or executing object destructors.

  • 当主线程退出时,不会执行除( try ... finally )的清除操作,标准I/O也不会被刷新。