首页 > 代码库 > 第九天 线程 进程 协程 队列

第九天 线程 进程 协程 队列

详细链接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 的参数,问题迎刃而解。

 

第九天 线程 进程 协程 队列