ProcessPoolExecutor对multiprocessing进行了高级抽象,暴露出简单的统一接口。
异步非阻塞 爬虫
对于异步IO请求的本质则是【非阻塞Socket】+【IO多路复用】:
"""

史上最牛逼的异步IO模块

"""
import select
import socket
import time
 
 
class AsyncTimeoutException(TimeoutError):
    """
    请求超时异常类
    """
 
    def __init__(self, msg):
        self.msg = msg
        super(AsyncTimeoutException, self).__init__(msg)
 
 
class HttpContext(object):
    """封装请求和相应的基本数据"""
 
    def __init__(self, sock, host, port, method, url, data, callback, timeout=5):
        """
        sock: 请求的客户端socket对象
        host: 请求的主机名
        port: 请求的端口
        port: 请求的端口
        method: 请求方式
        url: 请求的URL
        data: 请求时请求体中的数据
        callback: 请求完成后的回调函数
        timeout: 请求的超时时间
        """
        self.sock = sock
        self.callback = callback
        self.host = host
        self.port = port
        self.method = method
        self.url = url
        self.data = data
 
        self.timeout = timeout
 
        self.__start_time = time.time()
        self.__buffer = []
 
    def is_timeout(self):
        """当前请求是否已经超时"""
        current_time = time.time()
        if (self.__start_time + self.timeout) < current_time:
            return True
 
    def fileno(self):
        """请求sockect对象的文件描述符,用于select监听"""
        return self.sock.fileno()
 
    def write(self, data):
        """在buffer中写入响应内容"""
        self.__buffer.append(data)
 
    def finish(self, exc=None):
        """在buffer中写入响应内容完成,执行请求的回调函数"""
        if not exc:
            response = b''.join(self.__buffer)
            self.callback(self, response, exc)
        else:
            self.callback(self, None, exc)
 
    def send_request_data(self):
        content = """%s %s HTTP/1.0\r\nHost: %s\r\n\r\n%s""" % (
            self.method.upper(), self.url, self.host, self.data,)
 
        return content.encode(encoding='utf8')
 
 
class AsyncRequest(object):
    def __init__(self):
        self.fds = []
        self.connections = []
 
    def add_request(self, host, port, method, url, data, callback, timeout):
        """创建一个要请求"""
        client = socket.socket()
        client.setblocking(False)
        try:
            client.connect((host, port))
        except BlockingIOError as e:
            pass
            # print('已经向远程发送连接的请求')
        req = HttpContext(client, host, port, method, url, data, callback, timeout)
        self.connections.append(req)
        self.fds.append(req)
 
    def check_conn_timeout(self):
        """检查所有的请求,是否有已经连接超时,如果有则终止"""
        timeout_list = []
        for context in self.connections:
            if context.is_timeout():
                timeout_list.append(context)
        for context in timeout_list:
            context.finish(AsyncTimeoutException('请求超时'))
            self.fds.remove(context)
            self.connections.remove(context)
 
    def running(self):
        """事件循环,用于检测请求的socket是否已经就绪,从而执行相关操作"""
        while True:
            r, w, e = select.select(self.fds, self.connections, self.fds, 0.05)
 
            if not self.fds:
                return
 
            for context in r:
                sock = context.sock
                while True:
                    try:
                        data = sock.recv(8096)
                        if not data:
                            self.fds.remove(context)
                            context.finish()
                            break
                        else:
                            context.write(data)
                    except BlockingIOError as e:
                        break
                    except TimeoutError as e:
                        self.fds.remove(context)
                        self.connections.remove(context)
                        context.finish(e)
                        break
 
            for context in w:
                # 已经连接成功远程服务器,开始向远程发送请求数据
                if context in self.fds:
                    data = context.send_request_data()
                    context.sock.sendall(data)
                    self.connections.remove(context)
 
            self.check_conn_timeout()
 
 
if __name__ == '__main__':
    def callback_func(context, response, ex):
        """
        :param context: HttpContext对象,内部封装了请求相关信息
        :param response: 请求响应内容
        :param ex: 是否出现异常(如果有异常则值为异常对象;否则值为None)
        :return:
        """
        print(context, response, ex)
 
    obj = AsyncRequest()
    url_list = [
        {'host': 'www.google.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5,
         'callback': callback_func},
        {'host': 'www.baidu.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5,
         'callback': callback_func},
        {'host': 'www.bing.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5,
         'callback': callback_func},
    ]
    for item in url_list:
        print(item)
        obj.add_request(**item)
 
    obj.running()

python学习笔记之四-多进程&多线程&异步非阻塞的更多相关文章

  1. 多线程异步非阻塞之CompletionService

    引自:https://www.cnblogs.com/swiftma/p/6691235.html 上节,我们提到,在异步任务程序中,一种常见的场景是,主线程提交多个异步任务,然后希望有任务完成就处理 ...

  2. python 学习笔记九 队列,异步IO

    queue (队列) 队列是为线程安全使用的. 1.先入先出 import queue #测试定义类传入队列 class Foo(object): def __init__(self,n): self ...

  3. python学习笔记——multiprocessing 多进程组件-队列Queue

    1 消息队列 1.1 基本语法 消息队列:multiprocessing.Queue,Queue是对进程安全的队列,可以使用Queue实现对进程之间的数据传输:还有一个重要作用是作为缓存使用. Que ...

  4. python学习笔记——multiprocessing 多进程组件 进程池Pool

    1 进程池Pool基本概述 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态生成 ...

  5. python学习笔记——multiprocessing 多进程模块Process

    系统自带的fork模块创建的多进程是基于Linux或Unix平台的,而window平台并不支持: python中的multiprocess为跨平台版本的多进程模块,支持子进程.通信和共享数据.执行不同 ...

  6. python学习笔记(threading多线程)

    博主昨天优化了接口框架想着再添加些功能 想到对接口的性能压力测试 在工作过程中之前都是使用的工具 如:loadrunner.jmeter 想着这次准备用python实现对接口的性能压力测试 首先要实现 ...

  7. python学习笔记——multiprocessing 多进程组件 Pipe管道

    进程间通信(IPC InterProcess Communication)是值在不同进程间传播或交换信息. IPC通过有管道(无名管道 和 有名 / 命名管道).消息队列.共享存储 / 内容.信号量. ...

  8. 吴裕雄--天生自然python学习笔记:Python3 多线程

    多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条 ...

  9. python学习笔记之四:条件,循环和其他语句

    前面已经介绍过几种基本语句(print,import,赋值语句),下面我们来介绍条件语句,循环语句. 一. print和import的更多信息 1.1 使用逗号输出 A.打印多个表达式,用逗号隔开,会 ...

随机推荐

  1. angular 多端打包

    1.在environments文件夹里新建三个文件: //生产环境 environment.prod.ts: export const environment = { production: true ...

  2. vue教程自学笔记(二)

    三.模板语法 1.文本 数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值. 通过v-once指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新. 2.原始H ...

  3. gcc4.9.1新特性

    C family Support for colorizing diagnostics emitted by GCC has been added. The -fdiagnostics-color=a ...

  4. Eclipse导入war包二次开发

    有实际项目在跑的war包,却没有源码,苦于想查看源码,身处运维组为研发组看不起,拿不到源码,只能自己来反编译了. 其实在解压war包后,可以看到文件夹中,已经存在了jsp文件,但是却没有逻辑代码层(a ...

  5. VMware与Centos系统安装、重置root密码

    VMware与Centos系统安装   今日任务 .Linux发行版的选择 .vmware创建一个虚拟机(centos) .安装配置centos7 .xshell配置连接虚拟机(centos) 选择性 ...

  6. vuex实现原理

    一.Store的层次结构 Store,负责管理整个数据访问.修改等: 提高API: State,数据结构: 所有的getters.mutations,全部都注册到store里:结构大概是: { 'xx ...

  7. leetcode python 010

    #实现正则表达式匹配并支持'.'和'*'.#''匹配任何单个字符.#'*'匹配前面元素的零个或多个.#匹配应覆盖整个输入字符串(非部分).##Some examples:##isMatch(" ...

  8. Xenserver7.6修改root密码

    一:重启xenserver服务器 进入此界面时,先用上下建随便动下,解除4S倒计时,后按e键

  9. 剑指Offer 20. 包含min函数的栈 (栈)

    题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 题目地址 https://www.nowcoder.com/practice/4c77 ...

  10. Linux命令学习之路——内容剪切:cut

    使用者:所有角色 用法:cut [ -bcdfn ] [ --complement ] filename 作用:截取文件中的部分字段用于展示或存储到新文件中 应用场景: 1.内容展示 : 截取一个或多 ...