Python Threading、Queue模块学习


Threading模块 包括Thread、Condition、Event、Lock、Rlock、Semaphore等类。

1、Thread类可以实例化一个线程t,(target=) t.start()

Thread方法如下:

getName:返回线程t的名称、setName设置线程t的名称

isAlive:判断一个线程是否是活动的,也就是线程的状态在t.start和t.run之间

isDaemon/setDaemon:如果线程t是一个驻留程序   setDaemon(True)

join:其他调用线程(非t)会直接挂起,直到t结束,只能在t.start之后调用t.join

start:让线程t活动

run:run是运行线程t主函数的方法,thread的子类通常会覆盖run,如果不被覆盖,run将调用在创建t时传递的target参数

 

2、线程同步对象:

timeout:

lock/rlock:

 

 

Python的线程池实现

http://www.cnblogs.com/nsnow/archive/2010/04/18/1714596.html

1 #coding:utf-8
 2 
 3 #Python的线程池实现
 4 
 5 import Queue
 6 import threading
 7 import sys
 8 import time
 9 import urllib
10 
11 #替我们工作的线程池中的线程
12 class MyThread(threading.Thread):
13  def __init__(self, workQueue, resultQueue,timeout=30, **kwargs):
14   threading.Thread.__init__(self, kwargs=kwargs)
15   #线程在结束前等待任务队列多长时间
16   self.timeout = timeout
17   self.setDaemon(True)
18   self.workQueue = workQueue
19   self.resultQueue = resultQueue
20   self.start()
21 
22  def run(self):
23   while True:
24    try:
25     #从工作队列中获取一个任务
26     callable, args, kwargs = self.workQueue.get(timeout=self.timeout)
27     #我们要执行的任务
28     res = callable(args, kwargs)
29     #报任务返回的结果放在结果队列中
30     self.resultQueue.put(res+" | "+self.getName())    
31    except Queue.Empty: #任务队列空的时候结束此线程
32     break
33    except :
34     print sys.exc_info()
35     raise
36     
37 class ThreadPool:
38  def __init__( self, num_of_threads=10):
39   self.workQueue = Queue.Queue()
40   self.resultQueue = Queue.Queue()
41   self.threads = []
42   self.__createThreadPool( num_of_threads )
43 
44  def __createThreadPool( self, num_of_threads ):
45   for i in range( num_of_threads ):
46    thread = MyThread( self.workQueue, self.resultQueue )
47    self.threads.append(thread)
48 
49  def wait_for_complete(self):
50   #等待所有线程完成。
51   while len(self.threads):
52    thread = self.threads.pop()
53    #等待线程结束
54    if thread.isAlive():#判断线程是否还存活来决定是否调用join
55     thread.join()
56     
57  def add_job( self, callable, *args, **kwargs ):
58   self.workQueue.put( (callable,args,kwargs) )
59 
60 def test_job(id, sleep = 0.001 ):
61  html = ""
62  try:
63   time.sleep(1)
64   conn = urllib.urlopen('http://www.google.com/')
65   html = conn.read(20)
66  except:
67   print  sys.exc_info()
68  return  html
69 
70 def test():
71  print 'start testing'
72  tp = ThreadPool(10)
73  for i in range(50):
74   time.sleep(0.2)
75   tp.add_job( test_job, i, i*0.001 )
76  tp.wait_for_complete()
77  #处理结果
78  print 'result Queue\'s length == %d '% tp.resultQueue.qsize()
79  while tp.resultQueue.qsize():
80   print tp.resultQueue.get()
81  print 'end testing'
82 if __name__ == '__main__':
83  test()

condition:

wait:

event:

 

二、Queue模块,threading一般都是和Queue模块配合使用的,Queue产生一个队列,队列模式有三种:

FIFO先进先出队列: Queue.Queue(maxsize) 如果maxsize小于1就表示队列长度无限

LIFO先进后出队列:Queue.LifoQueue(maxsize)

优先级队列级别越低越先出来:Queue.PriorityQueue(maxsize)

1、FIFO先进先出队列的方法:

Queue.qsize(): 返回队列的大小

Queue.empty():如果队列为空,返回True,反之False

Queue.full():如果队列满了,返回True,反之False

Queue.get() //从队头删除并返回一个item,可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有item可用。如果队列为空且block为false,队列将引发Empty异常。

Queue.get_nowait():相当于Queue.get(False)

Queue.put() //在队尾插入一个item,put()有两个参数,第一个item为必需的,第二个block为可选参数,默认为1.如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发full异常。

Queue.put_nowait():相当于Queue.put(item,False)

Queue.task_done():在完成一项工作后,Queue.task_done()函数向任务已经完成的队列发送一个信号

Queue.join():等到队列为空时,再执行其他的操作

 

 

以下是一些基本观点和概念:

1.多线程采用的是分时复用技术,即不存在真正的多线程,cpu做的事是快速地切换线程,以达到类似同步运行的目的,因为高密集运算方面多线程是没有用的,但是对于存在延迟的情况(延迟IO,网络等)多线程可以大大减少等待时间,避免不必要的浪费。

2.原子操作:这件事情是不可再分的,如变量的赋值,不可能一个线程在赋值,到一半切到另外一个线程工作去了……但是一些数据结构的操作,如栈的push什么的,并非是原子操作,比如要经过栈顶指针上移、赋值、计数器加1等等,在其中的任何一步中断,切换到另一线程再操作这个栈时,就会产生严重的问题,因此要使用锁来避免这样的情况。比如加锁后的push操作就可以认为是原子的了……

3.阻塞:所谓的阻塞,就是这个线程等待,一直到可以运行为止。最简单的例子就是一线程原子操作下,其它线程都是阻塞状态,这是微观的情况。对于宏观的情况,比如服务器等待用户连接,如果始终没有连接,那么这个线程就在阻塞状态。同理,最简单的input语句,在等待输入时也是阻塞状态。

4.在创建线程后,执行p.start(),这个函数是非阻塞的,即主线程会继续执行以后的指令,相当于主线程和子线程都并行地执行。所以非阻塞的函数立刻返回值的~

 

 

 

对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue,是线程安全的,因此在满足使用条件下,建议使用队列。

队列适用于 “生产者-消费者”模型。双方无论数量多少,产生速度有何差异,都可以使用queue。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM