阻塞,非阻塞,同步,异步
进程运行的三个状态: 运行,就绪,阻塞.
执行的角度:
阻塞: 程序运行时,遇到了IO,程序挂起,cpu被切走.
非阻塞: 程序没有遇到IO,程序遇到IO但是我通过某种手段,让cpu强行运行我的程序.
提交任务的角度:
同步: 提交一个任务,自任务开始运行直到此任务结束(可能有IO),返回一个返回值之后,我在提交下一个任务.
异步: 一次提交多个任务,然后我就直接执行下一行代码.
返回结果如何回收?
给三个老师发布任务:
同步: 先告知第一个老师完成写书的任务,我从原地等待,等他两天之后完成了,告诉完事了,我在发布下一个任务......
异步:
直接将三个任务告知三个老师,我就忙我的我,直到三个老师完成之后,告知我.
同步调用,异步调用
1. 异步调用 # 异步调用返回值如何接收? 未解决. from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import os def task(i): print(f'{os.getpid()}开始任务') time.sleep(random.randint(1,3)) print(f'{os.getpid()}任务结束') return i if __name__ == '__main__': # 异步调用 pool = ProcessPoolExecutor() for i in range(10): pool.submit(task,i) pool.shutdown(wait=True) # shutdown: 让我的主进程等待进程池中所有的子进程都结束任务之后,在执行. 有点类似与join. # shutdown: 在上一个进程池没有完成所有的任务之前,不允许添加新的任务. # 一个任务是通过一个函数实现的,任务完成了他的返回值就是函数的返回值. print('===主') # 2. 同步调用 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import os def task(i): print(f'{os.getpid()}开始任务') time.sleep(random.randint(1,3)) print(f'{os.getpid()}任务结束') return i if __name__ == '__main__': # 同步调用 pool = ProcessPoolExecutor() for i in range(10): obj = pool.submit(task,i) # obj是一个动态对象,返回的当前的对象的状态,有可能运行中,可能(就绪阻塞),还可能是结束了. # obj.result() 必须等到这个任务完成后,返回了结果之后,在执行下一个任务. print(f'任务结果:{obj.result()}') pool.shutdown(wait=True) # shutdown: 让我的主进程等待进程池中所有的子进程都结束任务之后,在执行. 有点类似与join. # shutdown: 在上一个进程池没有完成所有的任务之前,不允许添加新的任务. # 一个任务是通过一个函数实现的,任务完成了他的返回值就是函数的返回值. print('===主') # 3 异步如何取结果??? # 方式一: 异步调用,统一回收结果. # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # import time # import random # import os # # def task(i): # print(f'{os.getpid()}开始任务') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}任务结束') # return i # # if __name__ == '__main__': # # # 异步调用 # pool = ProcessPoolExecutor() # l1 = [] # for i in range(10): # obj = pool.submit(task,i) # l1.append(obj) # # pool.shutdown(wait=True) # print(l1) # for i in l1: # print(i.result()) # print('===主') # 统一回收结果: 我不能马上收到任何一个已经完成的任务的返回值,我只能等到所有的任务全部结束统一回收. # 第二种方式: from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import os def task(i): print(f'{os.getpid()}开始任务') time.sleep(random.randint(1,3)) print(f'{os.getpid()}任务结束') return i if __name__ == '__main__': # 异步调用 pool = ProcessPoolExecutor() l1 = [] for i in range(10): obj = pool.submit(task,i) l1.append(obj) pool.shutdown(wait=True) print(l1) for i in l1: print(i.result()) print('===主')
异步调用+回调函数
浏览器工作原理, 向服务端发送一个请求,服务端验证你的请求,如果正确,给你的浏览器返回一个文件, # 浏览器接收到文件,将文件里面的代码渲染成你看到的漂亮美丽的模样. # 什么叫爬虫? # 1. 利用代码模拟一个浏览器,进行浏览器的工作流程得到一堆源代码. # 2. 对源代码进行数据清洗得到我想要数据. # import requests # ret = requests.get('http://www.baidu.com') # if ret.status_code == 200: # print(ret.text) """ # 版本一: # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # import time # import random # import os # import requests # # # def task(url): # '''模拟的就是爬取多个源代码 一定有IO操作''' # ret = requests.get(url) # if ret.status_code == 200: # return ret.text # # def parse(content): # '''模拟对数据进行分析 一般没有IO''' # return len(content) # # # if __name__ == '__main__': # '''串行 耗费时间长,不可取 # ret = task('http://www.baidu.com') # print(parse(ret)) # # ret = task('http://www.JD.com') # print(parse(ret)) # # ret = task('http://www.taobao.com') # print(parse(ret)) # # ret = task('https://www.cnblogs.com/jin-xin/articles/7459977.html') # print(parse(ret)) # # ''' # # 开启线程池,并发并行的执行 # url_list = [ # 'http://www.baidu.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.taobao.com', # 'https://www.cnblogs.com/jin-xin/articles/7459977.html', # 'https://www.luffycity.com/', # 'https://www.cnblogs.com/jin-xin/articles/9811379.html', # 'https://www.cnblogs.com/jin-xin/articles/11245654.html', # 'https://www.sina.com.cn/', # # ] # pool = ThreadPoolExecutor(4) # obj_list = [] # for url in url_list: # obj = pool.submit(task,url) # obj_list.append(obj) # # pool.shutdown(wait=True) # for res in obj_list: # print(parse(res.result())) # # ''' # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) ''' # print('===主') ''' # 版本一: # 1. 异步发出10个任务,并发的执行,但是统一的接收所有的任务的返回值.(效率低,不能实时的获取结果) # 2. 分析结果流程是串行,影响效率. # for res in obj_list: # print(parse(res.result())) ''' # 版本二: 针对版本一的缺点2,改进,让串行编程并发或者并行. # from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor # import time # import random # import os # import requests # # # def task(url): # '''模拟的就是爬取多个源代码 一定有IO操作''' # ret = requests.get(url) # if ret.status_code == 200: # return parse(ret.text) # # # def parse(content): # '''模拟对数据进行分析 一般没有IO''' # return len(content) # # # if __name__ == '__main__': # # # 开启线程池,并发并行的执行 # url_list = [ # 'http://www.baidu.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.taobao.com', # 'https://www.cnblogs.com/jin-xin/articles/7459977.html', # 'https://www.luffycity.com/', # 'https://www.cnblogs.com/jin-xin/articles/9811379.html', # 'https://www.cnblogs.com/jin-xin/articles/11245654.html', # 'https://www.sina.com.cn/', # # ] # pool = ThreadPoolExecutor(4) # obj_list = [] # for url in url_list: # obj = pool.submit(task, url) # obj_list.append(obj) # ''' # # 1 在开一个线程进程池,并发并行的处理. 再开一个线程进程池,开销大. # # 2 将原来的任务扩大, # 版本一: # 线程池设置4个线程, 异步发起10个任务,每个任务是通过网页获取源码, 并发执行, # 最后统一用列表回收10个任务, 串行着分析源码. # 版本二: # 线程池设置4个线程, 异步发起10个任务,每个任务是通过网页获取源码+数据分析, 并发执行, # 最后将所有的结果展示出来. # 耦合性增强了. # 并发执行任务,此任务最好是IO阻塞,才能发挥最大的效果 # ''' # pool.shutdown(wait=True) # for res in obj_list: # [obj1, obj2,obj3....obj10] # print(res.result()) # """ # 版本三: # 基于 异步调用回收所有任务的结果我要做到实时回收结果, # 并发执行任务每个任务只是处理IO阻塞的,不能增加新得功能. # 异步调用 + 回调函数 from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor import time import random import os import requests def task(url): '''模拟的就是爬取多个源代码 一定有IO操作''' ret = requests.get(url) if ret.status_code == 200: return ret.text def parse(obj): '''模拟对数据进行分析 一般没有IO''' print(len(obj.result())) if __name__ == '__main__': # 开启线程池,并发并行的执行 url_list = [ 'http://www.baidu.com', 'http://www.JD.com', 'http://www.JD.com', 'http://www.JD.com', 'http://www.taobao.com', 'https://www.cnblogs.com/jin-xin/articles/7459977.html', 'https://www.luffycity.com/', 'https://www.cnblogs.com/jin-xin/articles/9811379.html', 'https://www.cnblogs.com/jin-xin/articles/11245654.html', 'https://www.sina.com.cn/', ] pool = ThreadPoolExecutor(4) for url in url_list: obj = pool.submit(task, url) obj.add_done_callback(parse) ''' 线程池设置4个线程, 异步发起10个任务,每个任务是通过网页获取源码, 并发执行, 当一个任务完成之后,将parse这个分析代码的任务交由剩余的空闲的线程去执行,你这个线程继续去处理其他任务. 如果进程池+回调: 回调函数由主进程去执行. 如果线程池+回调: 回到函数由空闲的线程去执行. ''' # 异步 回调是一回事儿? # 异步站在发布任务的角度, # 站在接收结果的角度: 回调函数 按顺序接收每个任务的结果,进行下一步处理. # 异步 + 回调: # 异步处理的IO类型. # 回调处理非Io
来源:https://www.cnblogs.com/-777/p/11416112.html