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是协程池大小,默认所有任务。

  • 相关阅读:
    Servlet页面跳转实现方法的区别
    谈JSP与XML的交互
    xml可以用做什么?
    Struts1.2入门知识
    做java web 开发的简单项目必须具备的知识
    Web工程师必备的18款工具
    css的四种调用方式
    jQuery Utilities
    历年考研数学常考题型考试必备
    。net思维导图
  • 原文地址:https://www.cnblogs.com/shld/p/9477830.html
Copyright © 2011-2022 走看看