美文网首页
关于并发执行及返回结果对比 (py版)

关于并发执行及返回结果对比 (py版)

作者: hugoren | 来源:发表于2019-04-24 17:23 被阅读0次

    前言

    py的世界里虽有GIL,但是进程,线程的使用还是有一些用武之地的.
    本文对比的是
    

    threading
    multiprocessing,
    concurrent.futures
    asyncio(3.5 版本以后的协程)
    gevent(常称monkey_patch)

    至于源码,有兴趣的,研究研究,还是很有收获的。改天再开篇。
    asyncio 是基于yield魔改的,整体的生态还不成熟,常被吐槽, 但据我目前使用来看,还是不错的。

    monkey_patch 经过长时间的线上验证,及代码不侵入性,性能还是挺可靠的。

    基于并发的考虑,这些都是不错的思路。

    threading 及 multiprocessing

    这两个的api差不多,要说不太一样的是,multiprocessing可带返回结果,threading返回结果,一般有两种思路是用队列或用类再封装一层

    multiprocessing返回结果

    def req_multi(url:str, result: dict):
        r = requests.get(url)
        result[url] = r
    
    def main_multi():
        process_manager = multiprocessing.Manager()
        result_dict = process_manager.dict()
        urls = ["http://www.baidu.com", "http://www.zhihu.com"]
        reqs = [multiprocessing.Process(target=req_multi, args=(i, result_dict)) for i in urls]
        [j.start() for j in reqs]
        [j.join() for j in reqs]
        print(result_dict)
    

    结果

    ![image.png](https://img.haomeiwen.com/i1500770/b608536e103201be.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    

    threading返回结果

    queue的方式

    q = queue.Queue()
    
    def req_threading(url: str):
        r = requests.get(url)
        q.put({url: r})
    
    def main_threading_queue():
        urls = ["http://www.baidu.com", "http://www.zhihu.com"]
        results = [threading.Thread(target=req_threading, args=(i,)) for i in urls]
        [j.start() for j in results]
        [k.join() for k in results]
        while q:
            print(q.get())
    
    

    class封装的方式

    class MainThread(threading.Thread):
        def __init__(self, fn_name: str, url: list):
            super(MainThread, self).__init__()
            self.fn_name = fn_name
            self.url = url
            self.result = {}
    
        def run(self):
            for i in self.url:
                r = requests.get(i)
                self.result[self.fn_name] = r
    
    

    异步的方式import concurrent.futures

    def main_future():
        urls = ["http://www.baidu.com", "http://www.zhihu.com"]
        pool = concurrent.futures.ProcessPoolExecutor(max_workers=2)
        results = [pool.submit(req_futrue, i) for i in urls]
        # results = [pool.map(req_futrue, urls)]
        r = [i.result(timeout=10) for i in  results]
        print(r)
    
    

    asyncio

    import gevent
    from gevent import socket
    # from gevent import monkey; monkey.patch_all()
    import time
    start_time = time.time()
    
    
    async def main_gevnet():
    
        urls = ["http://www.baidu.com", "http://www.baidu.com"]
        # jobs_1 = [gevent.spawn(req_1, i )for i in urls]
        # jobs_2 = [gevent.spawn(req_2, i )for i in urls]
        # for j in jobs_1:
        #     j.start()
        #     j.join()
        # for k in jobs_2:
        #     k.start()
        #     k.join()
        job_1 = req_1("http://www.baidu.com")
        job_2 = req_2("http://www.baidu.com")
    
    import asyncio
    for i in range(100):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main_gevnet())
    print(time.time() - start_time)
    

    gevent

    import gevent
    from gevent import socket
    # from gevent import monkey; monkey.patch_all()
    import time
    start_time = time.time()
    
    
    async def main_gevnet():
    
        urls = ["http://www.baidu.com", "http://www.baidu.com"]
        jobs_1 = [gevent.spawn(req_1, i )for i in urls]
        jobs_2 = [gevent.spawn(req_2, i )for i in urls]
        for j in jobs_1:
            j.start()
            j.join()
        for k in jobs_2:
            k.start()
            k.join()
        # job_1 = req_1("http://www.baidu.com")
        # job_2 = req_2("http://www.baidu.com")
    

    相关文章

      网友评论

          本文标题:关于并发执行及返回结果对比 (py版)

          本文链接:https://www.haomeiwen.com/subject/kytngqtx.html