python多线程编程,一般使用thread和threading模块。thread模块想对较底层,threading模块对thread模块进行了封装,更便于使用。所有,通常多线程编程使用threading模块。
(一)threading模块
Thread 线程类,这是我们用的最多的一个类,你可以指定线程函数执行或者继承自它都可以实现子线程功能;
Timer与Thread类似,但要等待一段时间后才开始运行;
Lock 锁原语,这个我们可以对全局变量互斥时使用;
RLock 可重入锁,使单线程可以再次获得已经获得的锁;
Condition 条件变量,能让一个线程停下来,等待其他线程满足某个“条件”;
Event 通用的条件变量。多个线程可以等待某个事件发生,在事件发生后,所有的线程都被激活;
Semaphore为等待锁的线程提供一个类似“等候室”的结构;
BoundedSemaphore 与semaphore类似,但不允许超过初始值;
Queue:实现了多生产者(Producer)、多消费者(Consumer)的队列,支持锁原语,能够在多个线程之间提供很好的同步支持。
(1)threading.Thread类
getName(self) 返回线程的名字
isAlive(self) 布尔标志,表示这个线程是否还在运行中
isDaemon(self) 返回线程的daemon标志
join(self, timeout=None) 程序挂起,直到线程结束,如果给出timeout,则最多阻塞timeout秒
run(self) 定义线程的功能函数
setDaemon(self, daemonic) 把线程的daemon标志设为daemonic
setName(self, name) 设置线程的名字
start(self) 开始线程执行
(2)threading.Queue类
Queue队列
LifoQueue后入先出(LIFO)队列
PriorityQueue 优先队列
(二)线程的创建
线程的创建一般有两种:①将创建的函数传递进threading.Thread()对象。②继承threading.Thread类,通常重写run()方法。
(1)使用threading.Thread(),实例化一个线程
# -*- coding: utf-8 -*-
import threading
# 使用threading.Thread(),实例化一个线程
def T():
print threading.current_thread().getName()
# 创建线程对象
t1 = threading.Thread(target=T, name='tt11')
# 启动线程
t1.start()
t1.join()
(2)创建threading.Thread 的子类, 并覆盖run() 方法
# -*- coding: utf-8 -*-
import threading
# 创建threading.Thread 的子类, 并覆盖run() 方法
class T(threading.Thread):
# 重写父类run()方法
def run(self):
print self.getName()
# 实例化线程,并运行
t1 = T()
t1.start()
(3)例子
# -*- coding: utf-8 -*-
import threading
class T(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
pass
def main():
t = T()
t.start()
if __name__ == '__main__':
main()
(4)join方法
用来阻塞上下文,直到该线程结束。
def join(self, timeout=None):
pass
(5)setDaemon方法
守护线程
当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程就分兵两路,
当主线程完成想退出时,会检验子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。
但是有时候我们需要的是,只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,
这时就可以用setDaemon方法,并设置其参数为True。
(三)共享资源的访问
共享资源,互斥与同步。
(1)简单的threading.Lock() 锁
# -*- coding: utf-8 -*-
import threading
counter = 0
mutex = threading.Lock()
class T(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
# 全局变量
global counter, mutex
time.sleep(1)
# 获得加锁
if mutex.acquire():
counter += 1
# 释放锁
mutex.release()
def main():
t = T()
t.start()
if __name__ == '__main__':
main()
当一个线程调用Lock对象的acquire()方法获得锁时,这把锁就进入“locked”状态。
因为每次只有一个线程1可以获得锁,所以如果此时另一个线程2试图获得这个锁,该线程2就会变为“blo同步阻塞状态。
直到拥有锁的线程1调用锁的release()方法释放锁之后,该锁进入
“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。
(2)可重入锁 threading.RLock()
当线程在获得加锁之后,又需要共享资源,需要再次加锁。但...
# -*- coding: utf-8 -*-
import threading
counter = 0
mutex = threading.Lock()
# mutex = threading.RLock()
class T(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
# 全局变量
global counter, mutex
time.sleep(1)
# 获得加锁
if mutex.acquire():
counter += 1
# 再次加锁
if mutex.acquire():
counter += 1
mutex.release()
# 释放锁
mutex.release()
def main():
t = T()
t.start()
if __name__ == '__main__':
main()
此时程序会挂起,也就是形成了最简单死锁。
在Python中为了支持在同一线程中多次请求同一资源,引入了‘可重入锁’。
count 记录了acquire的次数,从而使得资源可以被多次require。
直到一个线程所有的acquire都被release,其他的线程才能获得资源。
# 源代码
def RLock(*args, **kwargs):
return _RLock(*args, **kwargs)
class _RLock(_Verbose):
def __init__(self, verbose=None):
_Verbose.__init__(self, verbose)
self.__block = _allocate_lock()
self.__owner = None
self.__count = 0
(3)使用Condition实现复杂的同步
Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。
使用Condition的主要方式为:
线程首先acquire一个条件变量,然后判断一些条件。
如果条件不满足则wait;
如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。
不断的重复这一过程,从而解决复杂的同步问题。
一个经典的例子。生产者消费者问题。(理解上述,代码其实很简单。)
import threading
import time
condition = threading.Condition()
products = 0
class Producer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products < 10:
products += 1;
print "Producer(%s):deliver one, now products:%s" %(self.name, products)
condition.notify()
else:
print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)
condition.wait();
condition.release()
time.sleep(2)
class Consumer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products > 1:
products -= 1
print "Consumer(%s):consume one, now products:%s" %(self.name, products)
condition.notify()
else:
print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)
condition.wait();
condition.release()
time.sleep(2)
if __name__ == "__main__":
for p in range(0, 2):
p = Producer()
p.start()
for c in range(0, 10):
c = Consumer()
c.start()
(4)使用 threading.Event 实现线程间通信
使用threading.Event可以使一个线程等待其他线程的通知,我们把这个Event传递到线程对象中,
Event默认内置了一个标志,初始值为False。
一旦该线程通过wait()方法进入等待状态,直到另一个线程调用该Event的set()方法将内置标志设置为True时,
该Event会通知所有等待状态的线程恢复运行。
import threading
import time
class MyThread(threading.Thread):
def __init__(self, signal):
threading.Thread.__init__(self)
# 初始化
self.singal = signal
def run(self):
print "I am %s,I will sleep ..."%self.name
# 进入等待状态
self.singal.wait()
print "I am %s, I awake..." %self.name
if __name__ == "__main__":
# 初始 为 False
singal = threading.Event()
for t in range(0, 3):
thread = MyThread(singal)
thread.start()
print "main thread sleep 3 seconds... "
time.sleep(3)
# 唤醒含有signal, 处于等待状态的线程
singal.set()
-- 2014年08月23日03:53:22
来源:oschina
链接:https://my.oschina.net/u/1170156/blog/305807