day37

阻塞、非阻塞、同步、异步

进程运行的三个状态:运行、就绪、阻塞

执行的角度
  • 阻塞:程序运行时,遇到了IO,程序挂起,CPU被切走
  • 非阻塞:程序没有遇到IO,程序遇到IO但是我通过某种手段,让CPU强行运行我的程序
提交任务的角度
  • 同步:提交一个任务,自任务开始运行直到此任务结束(可能有IO),返回一个返回值之后,我再提交下一个任务

  • 异步:一次提交多个任务,然后直接执行下一行代码,等待任务结果

    返回结果如何回收?

案例:给三个老师发布任务:

  • 同步:先告知第一个老师完成写书的任务,我从原地等待,等他两天之后完成了,告诉完事了,我再发布下一个任务。。。。
  • 异步:直接将三个任务告知三个老师,我就忙我的,直到三个老师完成之后,告知我

同步调用、异步调用

同步调用
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(4)
for i in range(6):
obj = pool.submit(task, i)
# obj是一个动态对象,返回当前对象的状态,有可能运行中(running),可能pending(就绪或阻塞),还可能使结束了(finished returned int)
# obj.result()必须等到这个任务完成后,返回结果之后再执行下一个任务
print(obj.result()) # obj.result()没有返回值
pool.shutdown(wait=True)
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(4)
for i in range(6):
pool.submit(task, i) pool.shutdown(wait=True)
# shutdown:让我的主进程等待进程池中所有的子进程都结束之后再执行下面的代码,优点类似于join
# shutdown:在上一个进程池没有完成所有的任务之前,不允许添加新的任务
# 一个任务是通过一个函数实现的,任务完成了他的返回值就是函数的返回值
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(4)
lst = []
for i in range(6):
obj = pool.submit(task, i)
lst.append(obj)
pool.shutdown()
for i in lst:
i.result() # print(i.result())
print("===主")

第二种方式:异步调用+回调函数

异步调用+回调函数

浏览器工作原理
  • 向服务端发送一个请求,服务端验证你的请求,如果正确,给你的浏览器返回一个文件
  • 浏览器接收到文件,将文件里面的代码渲染成你看到的漂亮美丽的模样
爬虫的工作原理
  • 利用代码模拟一个浏览器,进行浏览器的工作流程得到一堆源代码

  • 对源代码进行数据清洗得到我想要的数据

  • 页面请求的状态值

    分别有:200请求成功、303重定向、400请求错误、401未授权、403禁止访问、404文件未找到、500服务器错误

  • 代码

import requests
ret = requests.get("http://www.baidu.com")
if ret.status_code == 200:
print(ret.text)
版本一

主代码

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import requests def task(url):
"""
模拟的是爬取多个源代码,一定有IO操作
:param url:
:return:
"""
ret = requests.get(url)
if ret.status_code == 200:
return ret.text def parse(content):
"""
模拟对数据进行分析,一般没有IO
:param content:
:return:
"""
return len(content) if __name__ == '__main__':
# 串行 耗费时间长,不可取
# ret1 = task("http://www.baidu.com")
# print(parse(ret1))
# ret2 = task("http://www.JD.com")
# print(parse(ret2))
# ret3 = task("http://www.taobao.com")
# print(parse(ret3))
# ret4 = task("https://www.cnblogs.com/jin-xin/articles/7459977.html")
# print(parse(ret4)) # 开启线程池,并发并行的执行
url_list = [
"http://www.baidu.com",
"http://www.JD.com",
"http://www.taobao.com",
"https://www.cnblogs.com/jin-xin/articles/7459977.html",
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/9811379.html',
'https://www.cnblogs.com/jin-xin/articles/11245654.html',
'https://www.luffycity.com/'
]
pool = ThreadPoolExecutor(4)
obj_list = []
for url in url_list:
obj = pool.submit(task, url)
obj_list.append(obj) pool.shutdown(wait=True)
for i in obj_list:
print(parse(i.result()))
print("===主")

总结:

缺点:

  • 异步发出10个任务,并发的执行,但是统一接收了所有任务的返回值(效率低,不能实时的获取结果)

  • 分析结果流程是串行,影响了效率

    for res in obj_list:
    print(parse(res.result()))
版本二

针对版本一的缺点2进行改进,让串行变成并发或并行

解决方式

  • 再开一个线程进程池,并发并行的处理,再开一个线程进程池开销大
  • 将原来的任务扩大 (可以)

主代码

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import requests def task(url):
"""
模拟的是爬取多个源代码,一定有IO操作
:param url:
:return:
"""
ret = requests.get(url)
if ret.status_code == 200:
return parse(ret.text) def parse(content):
"""
模拟对数据进行分析,一般没有IO
:param content:
:return:
"""
return len(content) if __name__ == '__main__':
url_list = [
"http://www.baidu.com",
"http://www.JD.com",
"http://www.taobao.com",
"https://www.cnblogs.com/jin-xin/articles/7459977.html",
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/9811379.html',
'https://www.cnblogs.com/jin-xin/articles/11245654.html',
'https://www.luffycity.com/'
]
pool = ThreadPoolExecutor(4)
obj_list = []
for url in url_list:
obj = pool.submit(task, url)
obj_list.append(obj) pool.shutdown(wait=True)
for i in obj_list:
print(i.result())
print("===主")

总结:

版本一与版本二对比

版本一:

  • 线程池设置4个线程,异步发起10个任务,每个任务是通过网页获取源码+数据分析,并发执行
  • 最后统一用列表回收10个任务,串行着分析源码

版本二:

  • 线程池设置4个线程,异步发起10个任务,每个任务是通过网页获取源码+数据分析,并发执行
  • 最后把所有的结果展示出来

缺点:

  • 耦合性增强了
  • 并发执行任务,此任务最好是IO阻塞,才能发挥最大的效果
  • 获取源代码肯定有IO阻塞,清洗数据大部分没有IO阻塞,应该要分开不能组在一起
版本三

基于异步调用回收所有任务的结果我要做到实时回收结果

并发执行任务每个任务只是处理IO阻塞的,不能增加新的功能

异步调用+回调函数

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import requests def task(url):
"""
模拟的是爬取多个源代码,一定有IO操作
:param url:
:return:
"""
ret = requests.get(url)
if ret.status_code == 200:
return ret.text def parse(obj):
"""
模拟对数据进行分析,一般没有IO
:param content:
:return:
"""
print(len(obj.result())) if __name__ == '__main__':
url_list = [
"http://www.baidu.com",
"http://www.JD.com",
"http://www.taobao.com",
"https://www.cnblogs.com/jin-xin/articles/7459977.html",
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/7459977.html',
'https://www.cnblogs.com/jin-xin/articles/9811379.html',
'https://www.cnblogs.com/jin-xin/articles/11245654.html',
'https://www.luffycity.com/'
]
pool = ThreadPoolExecutor(4)
for url in url_list:
obj = pool.submit(task, url)
obj.add_done_callback(parse)

总结:

  • 线程池设置4个线程,异步发起10个任务,每个任务是通过网页获取源码,并发执行
  • 当一个任务完成之后,将parse这个分析代码的任务交由剩余的空闲的线程去执行,你这个线程继续去处理其他任务
    • 如果是进程池+回调:回调函数由主进程去执行
    • 如果是线程池+回调:回到函数由空闲的线程去执

异步与回调是一回事?

  • 异步:站在发布任务的角度,处理的是有IO阻塞的代码
  • 回调函数:站在接收结果的角度,按顺序接收每个任务的结果,进行下一步处理。处理没有IO阻塞的代码

day37——阻塞、非阻塞、同步、异步的更多相关文章

  1. 同步异步,阻塞非阻塞 和nginx的IO模型

    同步与异步 同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication).所谓同步,就是在发出一个*调用*时,在没有得 ...

  2. 异步|同步&阻塞|非阻塞

    异步|同步:区别在于发出一个功能调用时,是否马上得到返回结果 阻塞|非阻塞:区别在于调用结果返回之前,当前线程是否挂起 node.js:单线程.异步非阻塞模型 单线程与异步不矛盾,与并发是矛盾的 ht ...

  3. 阻塞非阻塞,同步异步四种I/O方式

    举一个去书店买书的例子吧: (同步)阻塞: 你去书店买书,到柜台告诉店员,需要买一本APUE,然后一直在柜台等.(阻塞) 店员拿到书以后交给你. (同步)非阻塞: 你去书店买书,到柜台告诉店员A,需要 ...

  4. 进程&线程 同步异步&阻塞非阻塞

    2015-08-19 15:23:38 周三 线程 线程安全 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码 线程安全问题都是由全局变量及静态变量引起的 若每个线程中对 ...

  5. I/O阻塞非阻塞,同步异步

    http://www.cnblogs.com/luotianshuai/p/5098408.html "阻塞"与"非阻塞"与"同步"与&qu ...

  6. 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor

    开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...

  7. 高性能IO设计模式之阻塞/非阻塞,同步/异步解析

    提到高性能,我想大家都喜欢这个,今天我们就主要来弄明白在高性能的I/O设计中的几个关键概念,做任何事最重要的第一步就是要把概念弄的清晰无误不是么?在这里就是:阻塞,非阻塞,同步,异步. OK, 现在来 ...

  8. Python番外之 阻塞非阻塞,同步与异步,i/o模型

    1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步:      所谓同步,就 ...

  9. JAVA 中BIO,NIO,AIO的理解以及 同步 异步 阻塞 非阻塞

    在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步 ...

  10. 008. 阻塞&非阻塞、同步&异步

    阻塞 非阻塞:关注的对象是调用者: 阻塞:调用者发起调用后,处于等待状态,直到该调用有返回: 非阻塞:调用者发起调用后,不需要等待返回,可以往下执行: 同步 异步:  关注的对象是被调用者: 同步:服 ...

随机推荐

  1. 是Mscoreei.dll的正确版本吗?

    在安装.NET 4.0或更高版本之后,您可能会注意到.NET进程有点不寻常.下面是用.NET 2.0编译器编译的简单“Hello World”可执行文件的加载模块的部分列表. 开始-结束模块名称 60 ...

  2. C++ EH Exception(0xe06d7363)----抛出过程

    C++ EH Exception是Windows系统VC++里对c++语言的throw的分类和定义,它的代码就是0xe06d7363.在VC++里其本质也是SEH结构化异常机制.在我们分析用户崩溃的例 ...

  3. windows 获取时间戳

    Windows 批处理时间戳 1.时间戳格式: 取年份: echo %date:~,% 取月份: echo %date:~,% 取日期: echo %date:~,% 取星期: echo %date: ...

  4. [bzoj1008] 越狱

    Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 数据 ...

  5. JavaScript的入门篇

    快速认识JavaScript 熟悉JavaScript基本语法 窗口交互方法 通过DOM进行网页元素的操作 学会如何编写JS代码 运用JavaScript去操作HTML元素和CSS样式 <!DO ...

  6. 我的Android前生今世之缘-学习经验-安卓入门教程(六)

    关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号 欢迎大家关注我的微信公众号:「醉翁猫咪」 据我所知,网上教学资料一堆一堆的,那么还有很多人说,如何学习? ...

  7. c++中二叉树的先序中序后序遍历

    c++中二叉树的先(前)序.中序.后序遍历 讲解版 首先先看一个遍历的定义(源自度娘): 所谓遍历(Traversal),是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问.访问结点所做的 ...

  8. gdb 调试core文件报错: in free () from /lib64/libc.so.6 找不到原因啊

    运行程序死掉  找不到原因啊..gdb 跟踪与堆栈信息 贴出来了 麻烦大佬们看一下,给个回复,不胜感激!! Core was generated by `./scene_s0037 10037'.Pr ...

  9. element ui input 输入时触发事件

    <el-form-item label="客户名" :label-width="labelWidth"> <el-input v-model= ...

  10. 在js中添加HTML类样式

    有时候需要给元素添加类样式,但又要保留之前的类,可以使用element.classList.add("类名");