Python之全局解释器锁:
对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个
线程在运行。在多线程环境中,Python 虚拟机按以下方式执行:
1. 设置GIL
2. 切换到一个线程去运行
3. 运行:
a. 指定数量的字节码指令,或者
b. 线程主动让出控制(可以调用time.sleep(0))
4. 把线程设置为睡眠状态
5. 解锁GIL
6. 再次重复以上所有步骤
Python中跟线程相关的模块:
thread:模块提供了基本的线程和锁的支持
threading:提供了更高级别,功能更强的线程管理的功能
Queue:允许用户创建一个可以用于多个线程之间共享数据的队列数据结构
提示:避免使用Thread模块
首先,更高级别的threading 模块更为先进,对线程的支持更为完善,而且使用thread 模块里的属性有可能会与threading 出现冲突。
其次,低级别的thread 模块的同步原语很少(实际上只有一个),而threading 模块则有很多。
再次:对于你的进程什么时候应该结束完全没有控制,当主线程结束时,所有的线程都会被强制结束掉,没有警告也不会有正常的清除工作
Thread模块和锁对象:
start_new_thread(function,args, kwargs=None) 产生一个新的线程,在新线程中用指定的参数和可选的kwargs 来调用这个函数。
allocate_lock() 分配一个LockType 类型的锁对象
exit() 让线程退出
LockType 类型锁对象方法
acquire(wait=None) 尝试获取锁对象
locked() 如果获取了锁对象返回True,否则返回False
release() 释放锁
Thead线程锁示例:
#!/usr/bin/env python
import thread
from time import sleep, ctime
loops = [4,2]
def loop(nloop, nsec, lock):
print 'start loop', nloop, 'at:', ctime()
sleep(nsec)
print 'loop', nloop, 'done at:', ctime()
lock.release()
def main():
print 'starting at:', ctime()
locks = []
nloops = range(len(loops))
for i in nloops:
lock = thread.allocate_lock()
lock.acquire()
locks.append(lock)
for i in nloops:
thread.start_new_thread(loop,
(i, loops[i], locks[i]))
for i in nloops:
while locks[i].locked(): pass
print 'all DONE at:', ctime()
if __name__ == '__main__':
main()
运行结果:D:/>python test.py
starting at: Sun May 08 10:16:55 2011
start loopstart loop 01 at:at: Sun May 08 10:16:55 2011Sun May 08 10:16:55 20
11
loop 1 done at: Sun May 08 10:16:57 2011
loop 0 done at: Sun May 08 10:16:59 2011
all DONE at: Sun May 08 10:16:59 2011
Threading类:
Thread 表示一个线程的执行的对象
Lock 锁原语对象(跟thread 模块里的锁对象相同)
RLock 可重入锁对象。使单线程可以再次获得已经获得了的锁(递归锁定)。
Condition 条件变量对象能让一个线程停下来,等待其它线程满足了某个“条件”。
如,状态的改变或值的改变。
Event 通用的条件变量。多个线程可以等待某个事件的发生,在事件发生后,
所有的线程都会被激活。
Semaphore 为等待锁的线程提供一个类似“等候室”的结构
BoundedSemaphore 与Semaphore 类似,只是它不允许超过初始值
Timer 与Thread 相似,只是,它要等待一段时间后才开始运行。
threading 模块支持守护线程,它们是这样工作的:守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求,它就在那等着。如果你设定一个线程为守护线程,就表示你在说这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。
Threading中Thread类常用的方法:
start() 开始线程的执行
run() 定义线程的功能的函数(一般会被子类重写)
join(timeout=None) 程序挂起,直到线程结束;如果给了timeout,则最多阻塞timeout 秒
getName() 返回线程的名字
setName(name) 设置线程的名字
isAlive() 布尔标志,表示这个线程是否还在运行中
isDaemon() 返回线程的daemon 标志
setDaemon(daemonic) 把线程的daemon 标志设为daemonic(一定要在调用start()函数前调用)
Thread 有三种方法可以用来创建线程: