Python 10:线程、进程、协程、异步io
1、概念
2、线程
3、进程
4、协程
5、事件件驱动模型
6、异步io
7、作业
一、概念
1、进程:
程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。
(程序以一个整体的形式暴露给操作系统。里面包含对各种资源的调用,内存的管理,网络接口的调用等,即对各种资源管理的集合)
程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。
启动一个进程会自动启动一个线程,进程里的第一个线程就是主线程,主线程可以创建子线程
2、线程:
线程是操作系统能够进行运算调度的最小单位,是一串指令的集合。
它被包含在进程之中,是进程中的实际运作单位。
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务
进程要操作cpu,至少创建一个线程
所有在同一个进程里的线程共享同一块内存空间
3、区别:
线程共享内存空间,进程内存是独立的
多个线程可以直接访问同一个进程的数据,多个子进程之间数据是相互独立的
同一个进程的线程之间可以直接交流,两个进程想通信必须通过一个中间代理来实现
创建新的线程很简单,创建新的进程需要对其父进程进行一次克隆
一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程
对于主线程的修改有可能会影响到其他线程的运行,但是对一个父进程的修改不会影响其他子进程
二、线程
1、调用
1 import threading 2 import time 3 def run(n): 4 print("task",n) 5 time.sleep(2) 6 t1 = threading.Thread(target=run,args=("t1",)) 7 t2 = threading.Thread(target=run,args=("t2",)) 8 t1.start() #并行 9 t2.start() 10 # run("t1") #未采用多线程:串行 11 # run("t2")
1 import threading 2 class MyThread(threading.Thread): 3 def __init__(self,n): 4 super(MyThread,self).__init__() 5 self.n = n 6 def run(self): 7 print("running task",self.n) 8 t1 = MyThread("t1") 9 t2 = MyThread("t2") 10 t1.start() 11 t2.start()
2、 Join 和 Daemon
1 import threading 2 import time 3 def run(n): 4 print("task",n,threading.current_thread()) #<Thread(Thread-1, started 1516)> 5 time.sleep(2) 6 start_time = time.time() 7 t_objs = [] 8 for i in range(10): 9 t = threading.Thread(target=run,args=("t-%s"%i,)) 10 t.start() 11 t_objs.append(t) 12 for t in t_objs: 13 t.join() #在主线程里等待子线程结果 14 print("who:",threading.current_thread(),threading.active_count()) #打印当前线程 <_MainThread(MainThread, started 6568)> 和当前活动线程数 15 print("cost:",time.time() - start_time) #为加join主线程与子线程并行,不会等子线程运行结束
1 import threading 2 import time 3 def run(n): 4 print("task",n,threading.current_thread()) #<Thread(Thread-1, started 1516)> 5 time.sleep(2) 6 start_time = time.time() 7 t_objs = [] 8 for i in range(10): 9 t = threading.Thread(target=run,args=("t-%s"%i,)) 10 t.setDaemon(True) #把当前线程设置为守护线程(主进程结束时不会等待守护线程执行完毕) 11 t.start() #一定要在执行之前设置 12 t_objs.append(t) 13 # for t in t_objs: 14 # t.join() #在主线程里等待子线程结果 15 print("who:",threading.current_thread(),threading.active_count()) #打印当前线程 <_MainThread(MainThread, started 6568)> 和当前活动线程数 16 print("cost:",time.time() - start_time) #为加join主线程与子线程并行,不会等子线程运行结束 17 18 #程序正常退出会等待所有进程执行完毕(守护进程除外)
3、GIL
全局解释器锁 :无论你启多少个线程,你有多少个cpu, Python在执行的时候在同一时刻只允许一个线程运行。
4、线程锁(互斥锁Mutex)
一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,有可能线程1还没修改完成但是线程2已经修改完成,为了避免线程自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。
1 import threading 2 def addNum(): 3 lock.accquire() #加锁:只允许一个线程修改数据,在这里把线程变成了串行 4 global num #在每个线程中都获取这个全局变量 5 print('--get num:',num ) 6 num +=1 #对此公共变量进行+1操作 7 lock.release() #释放锁 8 lock = threading.Lock() #申请锁 9 num = 0 #设定一个全局变量 10 thread_list = [] 11 for i in range(10): 12 t = threading.Thread(target=addNum) 13 t.start() 14 thread_list.append(t) 15 for t in thread_list: #等待所有线程执行完毕 16 t.join() 17 print('final num:', num )
5、递归锁
就是在一个大锁中还要再包含子锁,即有多个锁同时存在,当释放锁的时候系统自己混乱对不上号
递归锁的存在让程序能分辨出每个锁所对应的钥匙
1 import threading,time 2 3 def run1(): 4 print("grab the first part data") 5 lock.acquire() 6 global num 7 num +=1 8 lock.release() 9 return num 10 def run2(): 11 print("grab the second part data") 12 lock.acquire() 13 global num2 14 num2+=1 15 lock.release() 16 return num2 17 def run3(): 18 lock.acquire() 19 res = run1() 20 print('--------between run1 and run2-----') 21 res2 = run2() 22 lock.release() 23 print(res,res2) 24 25 26 if __name__ == '__main__': 27 28 num,num2 = 0,0 29 lock = threading.RLock() #递归锁() 30 for i in range(10): 31 t = threading.Thread(target=run3) 32 t.start() 33 34 while threading.active_count() != 1: 35 print(threading.active_count()) 36 else: 37 print('----all threads done---') 38 print(num,num2)
6、Semaphore(信号量)
互斥锁 :同时只允许一个线程更改数据,而Semaphore是同时只允许一定数量的线程更改数据
1 import threading,time 2 3 def run(n): 4 semaphore.acquire() 5 time.sleep(1) 6 print("run the thread: %s " %n) 7 semaphore.release() 8 9 semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行 10 for i in range(20): 11 t = threading.Thread(target=run,args=(i,)) 12 t.start() 13 while threading.active_count() != 1: 14 pass 15 else: 16 print('----all threads done---')
7、event(线程交互)
通过Event来实现两个或多个线程间的交互
1 import time 2 import threading 3 4 event = threading.Event() 5 def light(): 6 count = 0 7 event.set() 8 while True: 9 if count > 5 and count <= 10: #变成红灯 10 event.clear() #清空标志位 11 print("