首页 > 代码库 > 第九天 线程 进程 协程 队列
第九天 线程 进程 协程 队列
详细链接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 f13 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_time18 cc.append(c)19 print(cc)20 cost = time.time()-start_time21 print("cost",cost)22 23 24 输出:cost 3.009999990463257
6.将线程设置为守护线程,主进程执行完后程序就结束退出了,不会等守护线程执行结束
一、设置守护进程
import threadingimport timet_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_timeprint("cost",cost)输出:cost 0.0070040225982666016
二、不设置守护线程
import threadingimport timet_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_timeprint("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 num11 num = num +112 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_time26 cc.append(c)27 print(cc)28 cost = time.time()-start_time29 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_time21 print("cost",cost)22 23 输出:task24 task25 task26 task27 task28 cost 0.004001855850219726629 30 ******************31 32 ******************33 34 ******************35 36 ok37 38 39 ok40 ok41 task42 task43 task
10.线程标记位 event.set() event.clear() event.is_set()
import threadingimport timeevent = 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 += 1def car(name): while True: if event.is_set():#判断是否是标记位,代表绿灯 print("%s开车"%name) time.sleep(1) else: print("%s停车"%name) event.wait()#等待设置新的标记位,当新的标记位产生后,跳出elselight = 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 = http://www.mamicode.com/q.get()
except Queue.Empty:
break
我的本意是用队列为空时,退出循环,但实际运行起来,却陷入了死循环。这个问题和上面有点类似:Queue.get()默认的也是阻塞方式读取数据,队列为空时,不会抛出 except Queue.Empty ,而是进入阻塞直至超时。 加上block=False 的参数,问题迎刃而解。
第九天 线程 进程 协程 队列