一、全局锁
1、在Python中,Python代码的执行由Python虚拟机来控制,而在Python虚拟机中,同一时刻只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但在任意时刻,只有一个程序在CPU中运行。同样的,在Python解释器中可以“运行”多个线程,但在任意时刻,只有一个线程在Python解释器中运行。
2、对Python虚拟机的访问由全局解释器锁【GIL】来控制,正是这个锁能保证同一时刻只有一个线程在运行。
3、多线程环境中,Python虚拟机的执行方式为:
1. 设置GIL 2. 切换到一个线程去运行 3. 运行: a. 指定数量的字节码指令,或者 b. 线程主动让出控制(可以调用time.sleep(0)) 4. 把线程设置为睡眠状态 5. 解锁GIL 6. 再次重复以上所有步骤 |
二、线程模块
Python提供了【thread】和【threading】模块。在多线程编程中,建议使用【threading】模块,这是因为:
1、在【thread】模块中,当主线程退出时,其他没有被清除的线程没有运行结束就会被退出。但在【threading】模块中能确保所有的“重要的”子线程(这里的重要的子线程指的是守护线程)运行结束后,进程才会结束
2、在【threading】模块是更高级的线程模块,它不仅提供了Thread类,还提供了线程同步机制
thread模块
内建函数
1、thread.start_new_thread(function, args[, kwargs=None]) 这个函数用来启动一个线程,其参数含义分别为: function:线程任务函数 args:线程任务函数的参数【以元组的方式传入】 kwargs:可选的参数 2、thread.interrupt_main() 这个函数用来中断主线程 3、thread.exit() 这个函数用来退出线程 4、thread.get_ident() 这个函数用来获取线程标识号 5、thread.allocate_lock() 这个线程用来获取LockType对象 6、thread.stack_size([size]) 这个线程用来返回创建新线程栈容量,其参数含义为: |
LockType对象
1、lock.acquire([waitflag]) 这个函数用来申请锁对象,若是获得锁对象返回True,否则返回False 2、lock.release() 这个函数用来释放锁对象【使用该函数前提是获取锁对象】 3、lock.locked() |
示例:
>>> import thread
>>> sum = 0
/*****************线程任务函数**********************/
>>> def add(lock):
global sum #设置为全局变量
lock.acquire() #加锁
i = 1
while(i < 3):
sum = sum + 10
i = i + 1
id = thread.get_ident() #线程号
print "Thread ",id,"set sum = ",sum
lock.release() #释放锁
/***********************启动线程**************************/
>>> def startTask():
lock = thread.allocate_lock() #申请锁对象
task_0 = thread.start_new_thread(add,(lock,))
task_1 = thread.start_new_thread(add,(lock,))
/************************测试**************************/
>>> startTask()
>>> Thread 764 set sum = 20
Thread 5240 set sum = 40
threading模块
【threading】模块式以【thread】为基础,但提供更高的线程类以及同步机制。
内建函数
1、threading.activeCount() 这个函数用来获取【active Thread】的数目 2、threading.enumerate() 这个函数用来获取【active Thread】列表。注意:包括中断的线程以及还未开始的线程 3、threading.currentThread() 这个函数用来获取当前运行的【Thread object】 4、threading.settrace(func) 这个函数用来设置所有通过【threading】模块启动的线程的跟踪函数,该函数在【Thread Object】的【run】方法执行前被调用,其参数含义为: func:跟踪函数名 5、threading.setprofile(func) 这个函数用来设置所有通过【threading】模块启动的线程的profile函数 6、threading.Event() 这个工厂函数用来获取一个新的【Event Object】 7、threading.Lock() 这个工厂函数用来获取【LockType Object】 8、threading.RLock() 这个工厂函数用来获取【RLock Object】 9、threading.Condition() 这个工厂函数用来获取【Condition Object】 10、threading.Semaphore([value]) 这个工厂函数用来获取【Semaphore Object】 11、threading.BoundedSemaphore([value]) |
内建类
1、class threading.local 类似Java的ThreadLocal 2、class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}) 构造函数参数含义如下: target:Thread类中【run】函数调用的函数 name:指定线程的名,默认线程名格式为:【Thread-N】 args:target函数的参数 1)、start() 启动线程,值得注意的是:该方法只能被线程调用一次,否则抛出异常RuntimeError 2)、run() 线程任务函数。常被子类重写,类似Java Thread类的run函数 3)、is_alive() 判断线程是否【alive】 4)、setDaemon() 将线程设置为守护线程 3、class threading.Timer(interval, function, args=[], kwargs={}) Timer类继承threading.Thread类,其参数含义为: interval:线程时间执行时间间隔,以秒为单位 function:Thread类中run函数执行的目标函数 args:目标函数的参数 1)、cancel() |
示例
/***************************Timer实例************************/
>>> def putOutNumber():
id = threading.currentThread().getName()
print id,'Hello'
>>> def startTimer():
timer = threading.Timer(60,putOutNumber)
timer.start()
>>> startTimer()
>>> Thread-1 Hello
/****************继承Thread与Semaphore实例********************/
>>> import threading
>>> class MyThread(threading.Thread):
def __init__(self,name,semaphore):
threading.Thread.__init__(self,None,None,name,None)
self.semaphore = semaphore
def run(self): #override run function
self.semaphore.acquire()
i = 1
while(i < 3):
print self.getName(),' print ',i
i = i + 1
self.semaphore.release()
>>> def startTask():
semaphore = threading.Semaphore()
thread_0 = MyThread("Thread_0",semaphore)
thread_1 = MyThread("Thread_1",semaphore)
thread_0.start()
thread_1.start()
>>> startTask()
>>> Thread_0 print 1
Thread_0 print 2
Thread_1 print 1
Thread_1 print 2
/*********************进程之间进行通信************************/
>>> class ManagerThread(threading.Thread):
def __init__(self,name,event):
threading.Thread.__init__(self,None,None,name,None)
self.event = event
def run(self): #override run function
print self.getName(),' say ','go'
self.event.set()
>>> class PeopleThread(threading.Thread):
def __init__(self,name,event):
threading.Thread.__init__(self,None,None,name,None)
self.event = event
def run(self):
self.event.wait()
print self.getName(),' start ','go'
>>> def startTask():
event = threading.Event()
m_thread = ManagerThread("Manager",event)
p_thread = PeopleThread("People",event)
p_thread.start()
m_thread.start()
/*************************测试****************************/
>>> startTask()
>>> Manager say go
People start go
Mutex
内建类
1、class mutex.mutex mutex对象有两个属性:锁和队列。当锁没有被锁时,队列是空的。 /*********************mutex Object 函数********************/ 1)、mutex.test() 这个函数检测mutex是否被锁 2)、 mutex.testandset() 这个函数用来检测mutex是否被锁,若是没有锁住,则锁住并返回True,否则返回False。值得注意的是:这个函数是原子操作 3)、mutex.lock(function, argument) 这个函数用来执行函数function(argument)【前提是mutex没有被锁】。如果mutex锁被锁,则将function(argument)放入队列中 4)、mutex.unlock() |
示例
>>> import mutex
>>> def putOutTask(text):
print text
>>> def startTask():
m_metux = mutex.mutex()
m_metux.lock(putOutTask,'I am task_0')
m_metux.lock(putOutTask,'T am task_1')
m_metux.lock(putOutTask,'I am task_2')
m_metux.lock(putOutTask,'T am task_3')
m_metux.lock(putOutTask,'I am task_4')
m_metux.lock(putOutTask,'T am task_5')
while(m_metux.test()):
m_metux.unlock()
m_metux.unlock()
/**************************测试***************************/
>>> startTask()
I am task_0
T am task_1
I am task_2
T am task_3
I am task_4
T am task_5