进程 线程 协程
进程
''' 单核:多个任务:分时间片区执行任务----并发 多核:一个核执行一个任务(任务数和核数一样的情况)---并行,若任务太多,也是并发。 并发:分时间片区执行任务(假同时) 并行:一个核执行一个任务(任务数和核数一样的情况)--真同时 同步:在代码中指的是 依次执行---》单任务 异步:在代码中指单是 同时执行---》多任务 ---分析代码时都以并行来看 import multiprocessing 多进程实现: 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。 它是操作系统动态执行的基本单元,在传统的操作系统中,进程即是 基本的分配单元,也是基本的执行单元。 多进程:正在执行的程序 进程注意点: 例子:-------------------3_体验_边唱边跳.py------------------- ----进程的创建 import multiprocessing ..... if __name__ == '__main__': 进程对象名 = multiprocessing.Procrss(group = None,target = 任务名,args = (元组传参),kwargs(字典传参)) ---创建对象用到的参数:--------6_给进程任务传参.py--------- group:不用传,若要传就传 group = None target:函数名 target = 函数名 name:进程名,也可以不用设置,因为默认就有 , name = '取的名字' args:以元组方式给函数传参--->真元组 args = ( ,) kwargs:以字典形式给函数传参----》真字典 kwargs = { ; , : } ----进程的启动:进程对象名.start(),启动进程 ----进程的限制:进程对象.join()----等对象进程执行完,才执行下面的代码 ----进程提前结束:进程对象.terminate()----结束进程,需要在主进程中使用,不能在子进程函数中去结束自己 ----进程开启守护模式:进程对象.daemon = True,---开启守护模式,即如果设置了这个的进程,在主进程执行完后,和主进程一起结束,不管其执行完与否 ----程序强制退出;exit(),对多进程没有用,主进程还是要等子进程执行完后才结束 ----退出程序--------------4_论证主程序的退出.py------------- ----进程注意点: 资源不共享性与互不相联系性: 进程是独立的,当我们新建进程的时候,进程会自己开辟一个内存空间, 然后会把资源拷贝到自己的内存空间里面的去,因此变量的改变不会和其它 进程和主进程的变量产生干扰,因此子进程与子进程之前没有联系不能以打 印的顺序来推出进程执行的顺序,那是他们抢执行接口的结果,他们两者是 没有任何关系。 主进程: 不会等待子进程结束再去完成自己的代码,只发号命令,然后就开始执行自己的任务 主进程会等待所有子进程执行完毕后,再退出 ----进程编号和当前进程的获取 multiprocessing.current_process()----获取当前执行任务的进程对象 multiprocessing.current_process().pid----获取当前执行任务的进程对象的编码 os.getpid()----获取当前执行函数的编码 os.getppid()----获取当前执行进程的父进程编码 --子进程之间实现通信:queue que = multiprocessing.Queue(n) # n表示队列的大小,如果不写就是无限队列 基本语法 que.put('加入的值-任意值') que.get('取出的值’) # 相当于队列,先进先出 que.put_nowait() # 强行添加;若队列满了,再强行添加,会阻塞,报错 que.get_nowait() # 强行取值;若队列空了,再强行取值,报错 que.full() #返回队列是否是满的 que.empty() #返回队列是否为空 que.qsize() #返回队列的大小 # 此语法在mac上无法使用 注意点:当队列已经满了再往里面加值,会让代码执行产生阻塞,这个时候需要其它队列从离main取出一个值,这个队列后面的代码彩壳正常执行 实际例子--一个进程向队列中传值,一个进程取值另一个: import multiprocessing def add(que): print(multiprocessing.current_process().name)#打印当前执行任务的名字 que.put('a')#向队列中插入值 def take(que): print(multiprocessing.current_process().name)#打印当前执行任务的名字 print(que.get('a'))#向队列中取出值 if __name__=='__main__': #创建通信队列 que = multiprocessing.Queue(3) #创建子进程 p1 = multiprocessing.Process(target = add , args = (que,),name = '向队列中加入值')#传入队列对象 p2 = multiprocessing.Process(target = take, args = (que,),name = '向队列中取出值')#传入队列对象 #队列执行 p1.start() p2.start() ---代码执行: 向队列中加入值 向队列中取出值 a --进程池: 在定义的李时候里面会有很多进程,在任务分配的时候,程序根据任务量的多少来决定使用进程的个数与次数,提高执行效率。 --------注意:进程池里面所有的子进程都具有保护性,就是与主进程同生死,因此一定要记住使用join函数 --常用函数 pool.join() #我任务量就这么多了,你们等我弄完。 pool.close() #关闭进程池,这样可以避免后面的代码的执行,受到进程池任务分配完与否等稳定而收到干扰 pool.apply_async(任务名,args,kwargs) # 给池中进程分配任务 【asynschronous】异步 pool.apply() 同步执行,不推荐,因为这样和多进程顺序进行没有区别 实际例子--进程池的异步执行: #拷贝 ''' #多进程的体验 import multiprocessing import time import os a = [] def dance(): for i in range(5): a.append(i) #multiprocessing.current_process().pid os.getpid()-获取当前进程编号 os.getppid()--获取父进程编号 print('跳舞。。。。',a,multiprocessing.current_process(),multiprocessing.current_process().pid,os.getpid(),os.getppid()) time.sleep(1) def sing(): for i in range(5): a.append(i) print('唱歌。。。。',a,multiprocessing.current_process(),multiprocessing.current_process().pid,os.getpid(),os.getppid()) time.sleep(1) #有时候可能两个进程在某一瞬间同时执行---》唱歌 跳舞一起出现 if __name__ == '__main__': p1 = multiprocessing.Process(target = dance) p2 = multiprocessing.Process(target = sing) p1.start() p2.start() #文件的拷贝 import multiprocessing import os #初始路径 path = r'/Users/manblue/Downloads/a' targ = r'/Users/manblue/Downloads/b' #拷贝 def copy(name): abs_path = os.path.join(path,name) abs_targ = os.path.join(targ,name) with open(abs_path,'rb') as file_r: with open(abs_targ,'wb') as file_w: data = file_r.read() file_w.write(data) if __name__=="__main__": #创建进程池 pool = multiprocessing.Pool(3) if not os.path.exists(targ): os.mkdir(targ) name_li = os.listdir(path) #进程池分配任务 for name in name_li: pool.apply_async(copy,(name,)) #关闭进程池 pool.close() pool.join() ''' 拷贝文件---进程池---多层目录 1、运用什么方式更快-----多进程/多线程。------进程池 2、怎样拷贝文件-----对文件内部进行遍历----判断文件/文件夹 -----若文件夹是大文件,还得慢慢拷贝,就是while循环拷贝 3、创建或读取文件 ''' import multiprocessing import os def copy(name,path,targ): print(multiprocessing.current_process().name,"正在光荣对完成使命") #得到起始路径和目标路径的绝对路径 abs_path = os.path.join(path,name) abs_targ = os.path.join(targ,name) if os.path.isdir(abs_path): os.mkdir(abs_targ) name_li = os.listdir(abs_path) #判断是否是空 if name_li: path = abs_path targ = abs_targ for name in name_li: copy(name,path,targ) else: with open(abs_path,'r') as file_r: with open(abs_targ,'a') as file_w: while True: content = file_r.read(6) if content: file_w.write(content) else: print("拷贝完成") break if __name__ == '__main__': path = r'a' targ = r'b' #创立质量拷贝的方法渠道 pool = multiprocessing.Pool(3) #确保目标路径存在 if not os.path.exists(targ): os.mkdir(targ) #分配工作 name_li = os.listdir(path) for name in name_li: pool.apply_async(copy,(name,path,targ)) #拷贝完后得关闭进程池,且进程池里面对都是保护性质,即主进程执行完就跟着结束 pool.close() pool.join()#阻断主进程提前结束
线程
''' 线程 在一个进程内部,要同时干多件事情,就需要同时运行多个子任务,我们把进程内的这些子任务叫做线程 多线程就是为了同步完成多项任务(在单个程序中同时运行多个线程完成不同的任务和工作),不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率 线程存在于进程当中,同属一个进程下的线程之间共享进程资源 线程的创建: 线程对象名 = threading.Thread(group=None,target = dance, args = (...), kwargs = {...}, name = '...') 线程调用 线程对象.start() 线程的传参 创建线程传参:和进程一摸一样 group = None target = 任务名 args = () - -真元组 kwargs = {} - -真字典 获取活动线程的列表和获取活动线程的数量:活动线程,即正在执行的线程 活动线程列表: threading.enumerate() 活动线程数量: threading.active_count() 主线程会等子线程结束后再结束 设置保护属性(同生共死) # threading.Tread(...,deamon = True) # 线程对象.setDeamon(True) # 线程对象.deamon =True 子线程之间: 资源共享 问题:会出现抢占资源的问题 - --解决问题用互斥锁 互斥锁: 对共享数据进行锁定,保证同一时刻只能有一个线程去操作 可以解决线程互相抢资源的问题,被锁祝的资源只能当前线程用,等用完了解锁在抢 创建:lock_name = threading.Lock() 上锁:lock_name.acquires() ----尽量不要让任务中所有代码都锁住,只能锁住部分数据出错的地方 开锁:lock_name.release() 死锁:一直等待对方释放锁的情景,死锁一旦发生,程序就会停止响应 ------------------解决:判断的每一个分支都应该释放锁。 ''' ''' 获取活动线程列表 ----- threading.enumerate() 获取活动线程数量------threading.active_count() ''' import threading import time def dance(): for _ in range(5): print('dance',threading.current_thread().name) time.sleep(0.5) def sing(): for _ in range(5): print('sing',threading.current_thread().name) time.sleep(0.5) print(threading.enumerate(),threading.active_count()) t1 = threading.Thread(target = dance,name = 't1') t2 = threading.Thread(target = sing,name = 't2') t1.start() print(threading.enumerate(),threading.active_count()) t2.start() print(threading.enumerate(),threading.active_count())
协程
#进程(process)>线程(thread)>协程(生成器) ''' 协程--微线程 只有在耗时操作的时候需要使用协程(如网络请求 网络下载 网络上传如爬虫/其它iO操作) 是一种用户态的轻量级线程,协程的调度完全由用户控制(进程和线程都是由cpu 内核进行调度)。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方, 在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销, 可以不加锁的访问全局变量,所以上下文的切换非常快。-------即出现耗时操作时立马进行切换,让cpu不再闲着,高效率利用cpu 表现方式 - -1: while True: def 函数1: ...... yield def 函数2: ...... yield greenlet 和生成器差不多,只是这个执行时只需执行一个, 对象.switch(), 还是需要人工切换任务, import greenlet 对象名 = greenlet.greenlet(任务名也就是函数名),一个对象对应一个任务 执行,只需执行一个,另一个会自动跳转 - ----对象名.switch() gevent 可以自动识别延时操作比如sleep() 网络的请求 IO操作。如果发现在代码中有等待阻塞,那么会自动切到下一个任务中去 import gevent # 导入包 from gevent import monkey # 导入补丁 monkey.patch_all() # 打入补丁 def 函数1( ): 函数体(得有sllep() 网络请求 IO等操作) def 函数2( ): 函数体(得有sllep() 网络请求 IO等操作) g1 = gevent.spaen(函数名) g2 = gevent.spaen(函数名) g1.join() g2.join() ''' #下载并调用greenlet模块----优点:只需调用一次 缺点:需要人工switch切换 from greenlet import greenlet def homepage(): print("34") gr2.switch() print("12") gr3.switch() def bbs(): print("84") gr3.switch() print("13") def login(): print("56") gr1.switch() print("--end--") gr1 = greenlet(homepage) gr2 = greenlet(bbs) gr3 = greenlet(login) gr1.switch() #下载并调用greenlet模块 import gevent import time #如果没有这个补丁它不会来回跳转,需要等一个线程执行完后才执行另一个,这个补丁是后来对模块的修复,因此代码需要单独 from gevent import monkey#导入补丁 monkey.patch_all()#将补丁先打入到程序中 def func_01(): while True: print('we chat') gevent.sleep(0.5)# gevent会自动识别这些,然后会自动跳转到下一个任务 def func_02(): while True: print('chat 记录') gevent.sleep(0.5)# gevent会自动识别这些,然后会自动跳转到下一个任务 g1 = gevent.spawn(func_01)#创建gevent对象 g2 = gevent.spawn(func_02) #启动,固定语法 g1.join() # join()之后才跳转, g2.join() # join()之后才跳转,
进程 线程 协程
最新推荐文章于 2024-07-21 22:49:23 发布