第九天 线程 进程 协程 队列
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第九天 线程 进程 协程 队列相关的知识,希望对你有一定的参考价值。
详细链接http://www.cnblogs.com/alex3714/articles/5230609.html
1.线程:包含在进程中,是操作系统运算调度的最小单位,是一串指令的集合,直接与cpu交互
2进程:进程是一个程序各种资源的集合。操作系统通过管理这个集合进而运行程序,进程本身并不执行,进程通过调用线程来调度cpu。
3.不同点:
一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程
创建新线程很简单,但是创建一个子进程需要对父进程进行拷贝
线程共享内存,进程的内存是独立的
线程间可以直接交流数据,进程之间不能直接交流数据
4.多线程示例:
1 import threading 2 import time 3 def run(n,m): 4 print("task",n,m) 5 t1 = threading.Thread(target=run,args=(‘t1‘,‘f‘,)) #args是函数参数的集合,注意逗号 7 t2 = threading.Thread(target=run,args=(‘t2‘,‘g‘,)) 8 t1.start() 9 t2.start() 10 11 输出: 12 task t1 f 13 task t2 g
5.计算线程总共花费的时间:
threading.Thread.join() 等待start的线程运行结束
1 import threading 2 import time 3 t_list = [] 4 start_time = time.time() 5 def run(): 6 print("task") 7 time.sleep(3) 8 print("ok") 9 for i in range(50): 10 t = threading.Thread(target=run) 11 t.start() 12 t_list.append(t) 13 cc = [] 14 print(t_list) 15 for t in t_list: 16 t.join() 17 c = time.time()-start_time 18 cc.append(c) 19 print(cc) 20 cost = time.time()-start_time 21 print("cost",cost) 22 23 24 输出:cost 3.009999990463257
6.将线程设置为守护线程,主进程执行完后程序就结束退出了,不会等守护线程执行结束
一、设置守护进程
import threading import time t_list = [] start_time = time.time() def run(): print("task") time.sleep(3) print("ok") for i in range(50): t = threading.Thread(target=run) t.setDaemon(True) #将线程设置为守护线程 t.start() t_list.append(t) cost = time.time()-start_time print("cost",cost) 输出:cost 0.0070040225982666016
二、不设置守护线程
import threading import time t_list = [] start_time = time.time() def run(): print("task") time.sleep(3) print("ok") for i in range(50): t = threading.Thread(target=run) ##t.setDaemon(True) #未将线程设置为守护线程 t.start() t_list.append(t) for t in t_list: 去 ‘’ t.join() cost = time.time()-start_time print("cost",cost) 输出:cost 3.0090019702911377
7.在python2中,有时候线程会重复执行相同的操作,比如:从1加,一直,加到结果等于1000,可能会出现结果等于987或其他结果, 这时要使多线程变成串行。
线程锁(互斥锁Mutex)
例子:
1 import threading 2 import time 3 t_list = [] 4 start_time = time.time() 5 lock = threading.Lock() #先实例化一个锁 6 num = 0 7 def run(): #只需在这个函数内加锁即可 8 lock.acquire() #获取一把锁 9 print("task") 10 global num 11 num = num +1 12 time.sleep(1) 13 print("ok") 14 print(num) 15 lock.release() #将锁释放 16 for i in range(50): 17 t = threading.Thread(target=run) 18 t.setDaemon(True) 19 t.start() 20 t_list.append(t) 21 22 cc = [] 23 for t in t_list: 24 t.join() 25 c = time.time()-start_time 26 cc.append(c) 27 print(cc) 28 cost = time.time()-start_time 29 print("cost",cost) 30 31 32 33 输出:结果符合预期
8.threading.active_count() #获取当前活动线程的数量,返回一个数值
9.信号量:
sem = threading.BoundedSemaphore(5)#实例化信号量,指定同一时间只运行5个线程,当有一个线程运行完后,增加一个新的线程运行。
1 import threading 2 import time 3 sem = threading.BoundedSemaphore(5) 4 t_list = [] 5 start_time = time.time() 6 def run(): 7 # lock.acquire() 8 sem.acquire() 9 print("task") 10 time.sleep(1) 11 print(""" 12 ****************** 13 """) 14 print("ok") 15 sem.release() 16 for i in range(20): 17 t = threading.Thread(target=run) 18 t.start() 19 t_list.append(t) 20 cost = time.time()-start_time 21 print("cost",cost) 22 23 输出:task 24 task 25 task 26 task 27 task 28 cost 0.0040018558502197266 29 30 ****************** 31 32 ****************** 33 34 ****************** 35 36 ok 37 38 39 ok 40 ok 41 task 42 task 43 task
10.线程标记位 event.set() event.clear() event.is_set()
import threading import time event = threading.Event() def lighter(): count = 0 event.set()#设置标记位 while True: if count > 5 and count < 10: event.clear()#清除标记位 print("\\033[41;1m红灯\\033[0m") elif count > 10: event.set()#设置标记位 count = 0#count清0,重新累加 else: print("\\033[42;1m绿灯\\033[0m") time.sleep(1) count += 1 def car(name): while True: if event.is_set():#判断是否是标记位,代表绿灯 print("%s开车"%name) time.sleep(1) else: print("%s停车"%name) event.wait()#等待设置新的标记位,当新的标记位产生后,跳出else light = threading.Thread(target=lighter,) light.start() car1 = threading.Thread(target=car,args=(‘Tesla‘,)) car1.start() 输出:绿灯 Tesla开车 Tesla开车 绿灯 绿灯 Tesla开车 绿灯 Tesla开车 绿灯 Tesla开车 Tesla开车 绿灯 红灯 Tesla停车 红灯 红灯 红灯 绿灯 Tesla开车
11.队列
queue.
Queue
(maxsize=0) #先入先出
queue.
PriorityQueue
(maxsize=0) #存储数据时可设置优先级的队列
queue.
LifoQueue
(maxsize=0) #后入先出
创建一个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。
将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。
将一个值从队列中取出
q.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。
Python Queue模块有三种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。 class Queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。 class Queue.LifoQueue(maxsize)
3、还有一种是优先级队列级别越低越先出来。 class Queue.PriorityQueue(maxsize)
此包中的常用方法(q = Queue.Queue()):
q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作
一些需要注意的地方:
1. 阻塞模式
import Queue
q = Queue.Queue(10)
......
for i in range(10):
q.put(‘A‘)
time.sleep(0.5)
这是一段极其简单的代码(另有两个线程也在操作队列q),我期望每隔0.5秒写一个‘A‘到队列中,但总是不能如愿:间隔时间有时会远远超过0.5秒。原来,Queue.put()默认有 block = True 和 timeou 两个参数。当 block = True 时,写入是阻塞式的,阻塞时间由 timeou 确定。当队列q被(其他线程)写满后,这段代码就会阻塞,直至其他线程取走数据。Queue.put()方法加上 block=False 的参数,即可解决这个隐蔽的问题。但要注意,非阻塞方式写队列,当队列满时会抛出 exception Queue.Full 的异常。
2. 无法捕获 exception Queue.Empty 的异常
while True:
......
try:
data = q.get()
except Queue.Empty:
break
我的本意是用队列为空时,退出循环,但实际运行起来,却陷入了死循环。这个问题和上面有点类似:Queue.get()默认的也是阻塞方式读取数据,队列为空时,不会抛出 except Queue.Empty ,而是进入阻塞直至超时。 加上block=False 的参数,问题迎刃而解。
以上是关于第九天 线程 进程 协程 队列的主要内容,如果未能解决你的问题,请参考以下文章