zoukankan      html  css  js  c++  java
  • 装饰器实现多线程多协程并发编程

    有时候写一些规模不算大得小脚本的时候,特意去实现多线程和协程的编程是一件繁杂的事情,在轻量级的爬虫中我们希望用同步编程的思想来实现异步的执行,下面给出一个初步的解决方案,通过装饰器装饰函数使请求函数可以接受一个可迭代的链接容器。转载请注明出处。

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Date    : 2018-08-14 20:52:16
    # @Author  : Sheldon (thisisscret@qq.com)
    # @blogs   : 谢耳朵的派森笔记
    # @Link    : https://www.cnblogs.com/shld/
    from gevent.pool import Group
    from gevent import monkey
    
    monkey.patch_all()
    from concurrent.futures import ThreadPoolExecutor
    from functools import partial, wraps
    from multiprocessing import cpu_count
    
    
    def eqlike_split(src, num):
        len_ = len(src)
        div = len_ // num
        mod = len_ % num
        sdx = 0
        splist = []
        for p_len in ([1] * mod + [0] * (num - mod)):
            edx = p_len + div + sdx
            splist.append(src[sdx:edx])
            sdx = edx
        return splist
    
    
    def funcsplit(func, *args, **kw):
        """将args的首个元素分离出来,剩下的固定赋与为func函数的参数
        生成新的默认参数的函数,方便后续函数传参"""
    
        seed = args[0]
        new_args = args[1:]
        myfunc = partial(func, *new_args, **kw)
        return myfunc, seed
    
    
    def aioreq(func, urlist, aionum=None, **kw):
        """gevent异步协程池执行func,返回response生成器"""
    
        igroup = Group()
        return igroup.imap_unordered(func, urlist, maxsize=aionum)
    
    
    def thread_(func, seed, mtnum=2, **kw):
        """线程池池执行func,返回response生成器"""
    
        with ThreadPoolExecutor(mtnum) as executor:
            return executor.map(func, seed)
    
    
    def mtaio(func, seed, mtnum=None, aionum=None, **kw):
        """多线程协程并发执行func,返回两层深度的response生成器"""
    
        spnum = mtnum
        if not mtnum:
            spnum = cpu_count()
        new_seed = eqlike_split(seed, spnum)
        myaioreq = partial(aioreq, func, aionum=aionum)
        return thread_(myaioreq, new_seed, mtnum)
    
    
    def func2dec(decfunc=mtaio, mtnum=None, aionum=None):
        """使函数第一个参数接受变为参数迭代器的装饰器"""
    
        def decorator(func):
            @wraps(func)
            def wrapper(*args, **kw):
                fstuple = funcsplit(func, *args, **kw)
                return decfunc(*fstuple, mtnum=mtnum, aionum=aionum)
    
            return wrapper
    
        return decorator

    用法:func2dec(decfunc=mtaio,mtnum=None,aionum=None)作为装饰器装饰请求函数就可以了,decfunc可选多线程、协程、多线程协程;mtnum使线程池大小,默认cpu个数;aionum是协程池大小,默认所有任务。

  • 相关阅读:
    用js写留言信息的判断非空条件
    tp3.2中怎么访问分类及子分类下面的文章
    关于PHP中的 serialize () 和 unserialize () 的使用(即关于PHP中的值与已存储的表示的相互转换)
    iOS 8 Auto Layout界面自动布局系列2-使用Xcode的Interface Builder添加布局约束
    iOS深入学习(Block全面分析)
    面试4
    Android
    android适配不同分辨率的手机
    android分辨率适配
    Android屏幕适配全攻略(最权威的官方适配指导)
  • 原文地址:https://www.cnblogs.com/shld/p/9477830.html
Copyright © 2011-2022 走看看