进程、线程、协程对比
进程是操作系统资源分配的单位
线程是CPU调度的单位
进程切换需要的资源最大,效率很低
线程切换需要的资源一般,效率一般(当然在不考虑GIL的情况下)
协程切换任务资源小,效率高
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发
同步和异步
异步:调用在发出之后,这个调用就直接返回,不管有无结果:异步是过程
非阻塞:关注的是程序在等待调用结果(消息,返回值)时的状态,指在不能立刻得到结果之前,该调用不会阻塞当前线程
同步异步的区别
同步:一个服务的完成需要依赖其他服务时,只有等待被依赖的服务完成后,才算完成,这是一种可靠的服务序列。要么成功都成功,要么失败都失败,
服务的状态可以保持一致
异步:一个服务的完成需要依赖其他服务时,只通知其他依赖服务开始执行,而不需要等待被依赖的服务完成,此时该服务就算完成了。被依赖的服务是
否最终完成无法确定,因此他是一个不可靠的服务序列
消息通知中的同步和异步:
同步:当一个同步调用发出后,调用者一直等待返回消息(或者调用结果)通知后,才能进行后续的执行
异步:当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。在调用结束之后,通过消息回调来通知调用者是否调用成功。
阻塞和非阻塞区别:
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务,函数只有在得到结果之后,才会返回
非阻塞:非阻塞和阻塞的结果相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回
同步与异步是对应的,他们是线程之间的关系,两个线程之间要么是同步的,要么是异步的
阻塞与非阻塞是同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。
阻塞是使用同步机制的结果,非阻塞则是使用异步机制的结果
守护线程
setDaemon() 将当前线程设置成守护线程来守护主线程:-当主线程结束后,守护线程也就结束,不管是否执行完成
-应用场景:qq多个聊天窗口,就是守护线程
注意:需要在子线程开启的时候设置成守护线程,否则无效
import time,threading def dance(): for i in range(3): time.sleep(0.5) print("正在跳舞") def sing(): for i in range(3): time.sleep(0.8) print('正在唱歌') t1 = threading.Thread(target=dance) t2 = threading.Thread(target=sing) t1.setDaemon(True) t2.setDaemon(True) t1.start() t2.start() time.sleep(1) print("时间结束。ending") # 正在跳舞 # 正在唱歌 # 时间结束。ending # ------run------- 0 # ------run------- 1 # ------run------- 2 # 正在跳舞
-getName() 获取线程的名称
-setName() 设置线程的名称
-isAlive() 判断当前线程存活状态
import time,threading def dance(): for i in range(3): time.sleep(0.8) print('正在跳舞') def sing(): for i in range(3): time.sleep(0.8) print("正在唱歌") t1 = threading.Thread(target=dance) t2 = threading.Thread(target=sing) t1.setName('线程1') # t2.setName('线程2') print(t1.is_alive()) t1.start() print(t1.is_alive()) t2.start() print(t1.getName()) print(t2.getName()) # False # True # 线程1 # Thread-2 # ------run------- 0 # ------run------- 1 # ------run------- 2 # 正在跳舞 # 正在唱歌 # 正在唱歌 # 正在跳舞 # 正在唱歌 # 正在跳舞
threading.currentThread():返回当前的线程变量
threading.enumrate(): 返回一个包含正在运行的线程list,正在运行线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount():返回正在运行的线程数量,与len(threading.enumrate())有相同的结果
import threading,time def dance(): print('dance',threading.current_thread()) for i in range(3): time.sleep(0.5) print('正在跳舞') def sing(): print('sing',threading.current_thread()) for i in range(3): time.sleep(0.5) print('正在唱歌') t1 = threading.Thread(target=dance) t2 = threading.Thread(target=sing) print(threading.current_thread()) # print(threading.enumerate()) t1.start() t2.start() print('启动后的线程列表-->',threading.enumerate()) print(threading.active_count()) print(len(threading.enumerate())) # <_MainThread(MainThread, started 1536)> # dance <Thread(Thread-1, started 2000)> # sing <Thread(Thread-2, started 10484)> # 启动后的线程列表--> [<_MainThread(MainThread, started 1536)>, <Thread(Thread-1, started 2000)>, <Thread(Thread-2, started 10484)>] # 3 # 3 # 正在唱歌 # 正在跳舞 # 正在唱歌 # 正在跳舞 # 正在唱歌 # 正在跳舞
from threading import Thread class MyThread(Thread): def __init__(self,num): super(MyThread,self).__init__() self.num =num def run(self): for i in range(self.num): print('------run-------',i) if __name__ == '__main__': my = MyThread(3) my.start() # ------run------- 0 # ------run------- 1 # ------run------- 2
多线程开发的时候共享全局变量会带来资源竞争
# 多线程开发的时候共享全局变量会带来资源竞争的效果,也就是数据不安全 import threading,time g_num = 0 def func1(n): global g_num for i in range(n): time.sleep(0.01) g_num+=1 print('--func1---',g_num) def func2(n): global g_num for i in range(n): time.sleep(0.01) g_num+=1 print('--func2--',g_num) if __name__ == '__main__': t1 = threading.Thread(target=func1,args=(10000,)) t2 = threading.Thread(target=func2,args=(10000,)) t1.start()
线程锁
from threading import Thread,Lock # 互斥锁 lock = Lock() # 创建锁 lock.acquire() # 加锁 lock.release() # 释放锁 g_num = 0 def func1(n): global g_num for i in range(n): lock.acquire() g_num+=1 lock.release() print('--in func1--',g_num) def func2(n): global g_num for i in range(n): lock.acquire() g_num+=1 lock.release() print('--in func2--',g_num) if __name__ =='__main__': lock = Lock() t1 = Thread(target=func1,args=(10000,)) t2 = Thread(target=func2,args=(10000,)) t1.start() t2.start() # --in func1-- 10000 # --in func2-- 20000
# 在多个线程共享资源的时候,如果两个线程分别占有一部分资源,并且同时等待对方的资源,就会造成死锁现象 # 如果锁之间相互嵌套,就有可能出现死锁。因此尽量不要出现锁之间的嵌套 import threading,time printer_lock = threading.Lock() # 创建打印机锁 paper_lock =threading.Lock() #简历锁 class Printer(threading.Thread): def run(self): print('--printer start--') paper_lock.acquire() time.sleep(1) print("编写简历1") printer_lock.acquire() print("正在使用打印机1") printer_lock.release() paper_lock.release() print("printer end") class Paper(threading.Thread): def run(self): print("---paper start--") printer_lock.acquire() time.sleep(1) print('编写简历2') paper_lock.acquire() print("正在使用打印机2") printer_lock.release() paper_lock.release() print('paper end') if __name__ == '__main__': printer = Printer() paper = Paper() printer.start() paper.start() # --printer start-- # ---paper start-- # 编写简历2 # 编写简历1
# 一个threadLocal 变量虽然是全局变量,但是每个线程都只能读写自己线程的独立副本,互不干扰。 # threadLocal 解决了参数在一个线程中各个函数之间相互传递的问题 import threading local = threading.local() def func1(): print(local.num) def func2(): local.num = 5 local.num+=10 print(threading.current_thread()) func1() t1 = threading.Thread(target=func2) t1.start() # <Thread(Thread-1, started 3284)> # 15
线程和进程的对比
from multiprocessing import Process import time def func1(): start = time.time() i = 0 for i in range(20000000): i +=1 end = time.time() print("func1--total_time:",end-start) def func2(): start = time.time() i = 0 for i in range(20000000): i += 1 end = time.time() print("func2--total_time:", end - start) if __name__ == '__main__': p1 = Process(target=func1) p2 = Process(target=func2) p1.start() p2.start() # func2--total_time: 1.0018956661224365 # func1--total_time: 1.0268356800079346 import threading import time def func1(): start = time.time() i = 0 for i in range(20000000): i +=1 end = time.time() print("func1--total_time:",end-start) def func2(): start = time.time() i = 0 for i in range(20000000): i += 1 end = time.time() print("func2--total_time:", end - start) if __name__ == '__main__': t1 = threading.Thread(target=func1) t2 = threading.Thread(target=func2) t1.start() t2.start() # func1 - -total_time: 1.7554385662078857 # func2 - -total_time: 1.8083033561706543 import time num =0 start =time.time() for i in range(20000000): i+=1 end = time.time() print(end-start) #3.700019598007202
协程
# 协程切换一百万次 import time def func1(): start = time.time() for i in range(1000000): yield end = time.time() print("in func1 total_time:",end-start) def func2(g): start = time.time() for i in range(1000000): g.__next__() end = time.time() print('in func2 total_time:',end-start) g = func1() func2(g) # in func2 total_time: 0.11689877510070801
生产者模式和消费者模式
q = queue.Queue(3) 3表示只能存放3个数据
参数:maxsize 是队列中允许的最大项数。如果省略此参数,则无大小限制。返回值q是队列对象
2.put()方法,向队列中存放数据。如果队列已满,此方法阻塞直至有空间可用为止。
3.get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止
4.get_nowait():不等待,直到抛出异常
5.full()如果q已满,返回为True
6.q.empty()如果调用此方法时q为空,返回为True
7.qsize()获取队列中数据的个数
import queue q = queue.Queue(2) q.put("hello") q.put("world") print(q.full()) print(q.qsize()) print(q.get()) print(q.get()) # True # 2 # hello # world
import queue
import threading
import time
list = []
def produce(name):
for i in range(1,11):
print("%s生产了包子%d"%(name,i))
q.put(i)
time.sleep(0.5)
def custom(name):
while True:
print("%s吃了包子%d"%(name,q.get(timeout=10)))
if __name__ =='__main__':
q = queue.Queue()
t1 = threading.Thread(target=produce,args=('johnson',))
t2 = threading.Thread(target=custom,args=('may',))
t1.start()
t2.start()
# johnson生产了包子1
# may吃了包子1
# johnson生产了包子2
# may吃了包子2
# johnson生产了包子3
# may吃了包子3
# johnson生产了包子4
# may吃了包子4
# johnson生产了包子5
# may吃了包子5
# johnson生产了包子6
# may吃了包子6
# johnson生产了包子7
# may吃了包子7
# johnson生产了包子8
# may吃了包子8
# johnson生产了包子9
# may吃了包子9
# johnson生产了包子10
# may吃了包子10
练习
""" 创建两个进程:进程A和进程B,用jcq消息队列实现他们的通信。 1、进程A里创建两个线程:线程A1 、线程A2. 在进程A1里创建一个a列表 [1,2,3,4,5,6], 线程A1用消息队列将列表传递给线程A2,线程A2. 对列表进行筛选,删除掉奇数。然后用进程jcq消息队列发送给进程B 2、在进程B里创建两个线程:线程B1、线程B2 线程B2.接受进程A发过来的数据,并把这些数据,原封不动的用线程消息队列传递给线程B1 线程B1求出所有数的和并打印结果 """ from multiprocessing import Process,Queue from threading import Thread import queue def JcA(Q): qa = queue.Queue() a=[1, 2, 3, 4, 5, 6] xca1 = Thread(target=XcA1,args=(qa,a)) xca2 = Thread(target=XcA2,args=(qa,Q)) xca1.start() xca1.join() xca2.start() xca2.join() def XcA1(qa,lst): for i in lst: qa.put(i) def XcA2(qa,Q): for i in range(qa.qsize()): num = qa.get() if num%2==0: pass #放到进程消息队列中 Q.put(num) # 2、在进程B里创建两个线程:线程B1、线程B2 # 线程B2.接受进程A发过来的数据,并把这些数据,原封不动的用线程消息队列传递给线程B1 # 线程B1求出所有数的和并打印结果 def JcB(Q): qb = queue.Queue() xcb1 = Thread(target=XcB1, args=(qb,)) xcb2 = Thread(target=XcB2, args=(Q,qb)) xcb2.start() xcb2.join() xcb1.start() xcb1.join() def XcB1(qb): # pass #从线程消息队列中取数据,求出所有数的和并打印结果 sum = 0 for i in range(qb.qsize()): sum+=qb.get() print(sum) def XcB2(Q,qb): # pass#从进程队列中取数据,用线程消息队列传递给B1 for i in range(Q.qsize()): qb.put(Q.get()) if __name__ == '__main__': Q = Queue() pa = Process(target=JcA,args=(Q,)) pb = Process(target=JcB,args=(Q,)) pa.start() pa.join() pb.start()