Python 多线程 -thread threading Queue- 简单学习html
在实际工做过程当中,会出现须要并发的作一些事情,例如一台机器测到几千台机器的网络连通性,若是你单线程一台一台测的话,会花费不少的事情,不具备实时性,更不能在变化的时候马上感知当时网络的情况,这时多线程就是一个很好地选择。python已经给咱们封装好了多线程库thread和threading。python
thread:比较底层的模块
threading:Higher-level threading interfacegit
ps:建议使用threading模块
- 高级别的threading模块更为先进,对线程的支持更为完善
- 低级别的thread模块同步原语不多
- thread模块对线程何时结束彻底没有控制,当主线程结束时,全部线程都会强制结束github
模块函数web
start_new_thread(function, args,kwargs=None): 产生新的线程,args是function的参数,没有时写(),kwargs用来调用这个函数
allocate_lock(): 分配锁,LockType类型
exit(): 让线程退出canvas
LockType的操做ruby
acquire(wait=None):尝试获取锁
locked(): 获取了锁返回True,没有返回False
release():释放锁markdown
Demo1网络
$ cat t1.py import thread from time import sleep def a(): print "a start" sleep(2) print "a end" def b(): print "b start" sleep(2) print "b end" def main(): thread.start_new_thread(a,()) thread.start_new_thread(b,()) print "all done" if __name__ == "__main__": main() $ python t1.py all done b start a start
最终会发现,每一次运行出来的结果都有可能不一样,可是绝对不会出现“a end”和“b end”。这是为何呢,这里没有写让主线程停下来等全部子线程结束后再继续运行的代码,因此main线程在执行完print "all done"
就关闭了a和b两个线程。怎么办呢,能够在这里加一个sleep等待子进程执行完毕后再退出。多线程
Demo2: thread -- 多线程的演示 by sleep
$ cat t2.py import thread from time import sleep def a(): print "a start" sleep(2) print "a end" def b(): print "b start" sleep(2) print "b end" def main(): thread.start_new_thread(a,()) thread.start_new_thread(b,()) sleep (4) ----防止主进程过早退出,加sleep等待子进程执行完毕后再推出 print "all done" if __name__ == "__main__": main() $ python t1.py b start a start a end b end all done
可是假设咱们不知道子进程执行的时间怎么办,这就是锁的用武之地了。由于使用锁要比使用sleep()函数更为合理。以下所示:
Demo3: thread -- 多线程演示 by lock
实现方式为: 主线程初始化两个锁,分别传给两个函数,两个函数在执行完本身的代码后释放锁,主线程一直在轮询这个锁有没有释放,若是释放了就退出。
def a(lock, nsec): print "a starting at :", ctime() sleep(nsec) lock.release() -- 执行完以后释放锁 print "a end", ctime() def b(lock, nsec): print "b starting at :", ctime() sleep(nsec) lock.release() -- 执行完以后释放锁 print "b end", ctime() def main(): print "Demo Starting at:", ctime() locks = [] # Initialize lock -- 主线程先获取两个锁,占为己有 for i in range(2): lock = thread.allocate_lock() lock.acquire() locks.append(lock) # 每一个进程分配一个锁 thread.start_new_thread(a, (locks[0],2)) thread.start_new_thread(b, (locks[1],4)) for i in range(2): #一直在轮询,看锁有没有释放 while locks[i].locked(): pass print "all done at:", ctime()
最后的结果为:
$ python thread_demo.py Demo Starting at: Fri Aug 29 22:03:01 2014 a starting at : Fri Aug 29 22:03:01 2014 b starting at : Fri Aug 29 22:03:01 2014 a end Fri Aug 29 22:03:03 2014 b end Fri Aug 29 22:03:05 2014 all done at: Fri Aug 29 22:03:05 2014
不难发现,thread库的同步机制比较难用,一切都须要主进程来处理。而且没有守护进程,主进程一退,整个世界都会变得很清静。而threading库给咱们提供了守护进程。下面就来看看threading的简单用法。
threading提供了Thread类,还提供了不少很是好用的同步机制。感受重点了解Thread类就能够,多线程,也就是经过Thread类的多个实例。 类的主要方法有:
start():开始线程的执行。thread库里里面,是没有办法控制线程的开始的
join(timeout=None): 等待线程结束,有点相似Demo3中的轮询
run():定义线程的功能
感受上面是比较重要的,立马就会用到的。还有一些其余的:
getName():获取线程名
setName(name):设置线程名
isAlive(): 返回bool 表示线程是否在运行中
activeCount():返回运行中的线程数
currentThread():返回当前线程对象
enumerate():返回当前活动线程的列表
isDaemon(): 返回线程的Daemon标志
setDaemon(daemonic): 设置线程的Daemon标志,通常在start()函数前调用
settrace(func):为全部线程设置跟踪函数
setprofile(func): 为全部线程设置profile函数
Demo4 -- threading演示
def loop(i, nsec): print "thread %d starting at : %s" %(i, ctime()) sleep(nsec) print "thread %d end at : %s" %(i, ctime()) def main(): threads = [] loops = [2, 4] # 实例化进程 for i in range(len(loops)): t = threading.Thread(target = loop, args = (i, loops[i])) threads.append(t) for i in range(len(loops)): threads[i].start() for i in range(len(loops)): threads[i].join() print "all done"
最后的结果为:
thread 0 starting at : Sun Aug 31 13:31:28 2014 thread 1 starting at : Sun Aug 31 13:31:28 2014 thread 0 end at : Sun Aug 31 13:31:30 2014 thread 1 end at : Sun Aug 31 13:31:32 2014 all done
可见threading能够方便的控制线程的开始,以及等待每一个线程的结束,而且也不用设置锁,释放锁,这些都被threading库封装了,相比于thread要更高级一些。在实际的运维工程中,可能会须要多个线程执行相同的任务,这时须要一个任务池。每一个线程取任务池中取任务,执行,再取任务,再执行,一直到任务池为空,退出线程。这里就会用到下面要介绍的Queue库。
Queue模块能够用来实现多线程间通信,让各个线程共享数据,生产者把货物放到Queue中,供消费者(线程)去使用。在python3中,Queue模块被命名为queue。 Queue的对象有:
Queue.Queue(maxsize=0): 建立大小为maxsize的FIFO(First In First Out)-Queue对象,若是maxsize不设置,这个队列将是无限的。
Queue.LifoQueue(maxsize=0): 建立先入后出的对象,即栈, 在python2.6中加入 Queue.PriorityQueue(maxsize=0):有优先级的队列,在python2.6中加入
Queue对象的方法有:
qsize():返回队列的大小
empty():返回队列时候为空
full():返回队列是否满
put(item,block=0):向Queue对象中放数据,block不为0时,会一直等到队列中有控件为止
get(block=0):,同上,block不为0时,会一直等到队列中有数据为止
Demo5 -- Queue的使用演示:
场景: Queue里面放着一些整数,须要将整数取出,而且睡眠整数大小的时间,下面的demo中,是放了10个1,若是单线程的话须要10s
def work(q): while True: if q.empty(): return else: t = q.get() time.sleep(t) def main(): q = Queue.Queue() # 初始化一个Queue对象 for i in range(10): # 向Queue生产任务 q.put(1) work(q) if __name__ == "__main__": main()
最后的结果为:
time python threading_demo2.py real 0m10.085s user 0m0.060s sys 0m0.004s
单线程的话须要花费10s。
下面来经过多线程来处理Queue里面的任务:
def work(q): while True: if q.empty(): return else: t = q.get() time.sleep(t) def main(): q = Queue.Queue() for i in range(10): q.put(1) thread_num = 10 threads = [] for i in range(thread_num): t = threading.Thread(target = work, args = (q,)) # args须要输出的是一个元组,若是只有一个参数,后面加,表示元组,不然会报错 threads.append(t) for i in range(thread_num): threads[i].start() for i in range(thread_num): threads[i].join()
看看这下的结果为:
real 0m1.046s user 0m0.024s sys 0m0.020s
所以对python多线程,主要学会使用threading和Queue,应该就能够足以应付运维中的一些问题。