zoukankan      html  css  js  c++  java
  • python 并发 ThreadPoolExecutor

    正文:
    Executor是一个抽象类,子类:

    ThreadPoolExecutor和ProcessPoolExecutor ,一个线程池,一个进程池.

    future对象:在未来的某一时刻完成操作的对象.
    submit方法可以返回一个future对象,此对象直接返回,等线程函数执行完后把return的数据再set_result到future对象中; 

    下面实现了submit, map 与 as_completed的差别 , 下面的例子中都没有使用with ,实际使用时需要调用shutdown , 或用with

    #线程执行的函数
    def add(n1,n2):
        v = n1 + n2
        print('add :', v , ', tid:',threading.currentThread().ident)
        time.sleep(n1)
        return v
    #通过submit把需要执行的函数扔进线程池中.
    #submit 直接返回一个future对象
    ex = ThreadPoolExecutor(max_workers=3)      #制定最多运行N个线程
    f1 = ex.submit(add,2,3)
    f2 = ex.submit(add,2,2)
    print('main thread running')
    print(f1.done())                            #done 看看任务结束了没
    print(f1.result())                          #获取结果 ,阻塞方法

     注意 map 方法,返回是跟你提交序列是一致的. 是有序的

    #下面是map 方法的简单使用.  注意:map 返回是一个生成器 ,并且是*有序的*
    URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
    def get_html(url):
        print('thread id:',threading.currentThread().ident,' 访问了:',url)
        return requests.get(url)            #这里使用了requests 模块
    ex = ThreadPoolExecutor(max_workers=3)
    res_iter = ex.map(get_html,URLS)        #内部迭代中, 每个url 开启一个线程
    for res in res_iter:                    #此时将阻塞 , 直到线程完成或异常
        print('url:%s ,len: %d'%(res.url,len(res.text)))


     

    接下来,使用as_completed . 这个函数为submit 而生, 为啥呢?

    你总想通过一种办法来解决submit后啥时候完成的吧 , 而不是一次次调用future.done 或者 使用 future.result 吧.

    concurrent.futures.as_completed(fs, timeout=None) 返回一个生成器,在迭代过程中会阻塞,

    直到线程完成或者异常时,返回一个被set_result的Future对象.

    同时注意, map方法返回是有序的, as_completed 是那个线程先完成/失败 就返回

    #这是一个简单的 as_completed
    URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
    def get_html(url):
        time.sleep(3)
        print('thread id:',threading.currentThread().ident,' 访问了:',url)
        return requests.get(url)            #这里使用了requests 模块
    ex = ThreadPoolExecutor(max_workers=3)
    f = ex.submit(get_html,URLS[0])          #提交一个任务,放入线程池中,准备执行
    print('main thread running')
    for future in as_completed([f]):        #as_completed()接受一个可迭代的Future序列,返回一个生成器,在完成或异常时返回这个Future对象
        print('一个任务完成.')
        print(future.result())
    #as_completed 完整的例子
    #as_completed 返回一个生成器,用于迭代, 一旦一个线程完成(或失败) 就返回
    URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
    def get_html(url):
        time.sleep(1)
        print('thread id:',threading.currentThread().ident,' 访问了:',url)
        return requests.get(url)            #这里使用了requests 模块
    ex = ThreadPoolExecutor(max_workers=3)   #最多3个线程
    future_tasks = [ex.submit(get_html,url) for url in URLS]    #创建3个future对象
    for future in as_completed(future_tasks):       #迭代生成器
        try:
            resp = future.result()
        except Exception as e:
            print('%s'%e)
        else:
            print('%s has %d bytes!'%(resp.url, len(resp.text)))
    """
    thread id: 5160  访问了: http://www.baidu.com
    thread id: 7752  访问了: http://www.sina.com.cn
    thread id: 5928  访问了: http://www.qq.com
    http://www.qq.com/ has 240668 bytes!
    http://www.baidu.com/ has 2381 bytes!
    https://www.sina.com.cn/ has 577244 bytes!
    """

     wait 是阻塞函数,第一个参数和as_completed一样, 一个可迭代的future序列,返回一个元组 ,包含2个set , 一个完成的,一个未完成的

    """
    wait 例子
    参数:
        FIRST_COMPLETED    当任何未来完成或被取消时,该函数将返回。
        
        FIRST_EXCEPTION    当任何未来通过提出异常完成时,函数将返回。如果没有未来引发异常,那么它等同于 ALL_COMPLETED。
        
        ALL_COMPLETED(默认)      当所有future完成或被取消时,函数将返回。
    """
    URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
    def get_html(url):
        time.sleep(1)
        print('thread id:',threading.currentThread().ident,' 访问了:',url)
        return requests.get(url)            #这里使用了requests 模块
    ex = ThreadPoolExecutor(max_workers=3)   #最多3个线程
    future_tasks = [ex.submit(get_html,url) for url in URLS]    #创建3个future对象
    try:
        result = wait(future_tasks,return_when = fu.FIRST_COMPLETED)
        done_set = result[0]
        for future in done_set:
            resp = future.result()
            print('第一个网页任务完成 url:%s , len:%d bytes! ' % (resp.url, len(resp.text)))
    except Exception as e:
        print('exception :' , e)
     

    最后说一下回调:add_done_callback(fn) , 回调函数是在调用线程完成后再调用的,在同一个线程中.

    import os,sys,time,requests,threading
    from concurrent import futures
     
     
    URLS = [
            'http://baidu.com',
            'http://www.qq.com',
            'http://www.sina.com.cn'
            ]
     
    def load_url(url):
        print('tid:',threading.currentThread().ident,',url:',url)
        with requests.get(url) as resp:
            return resp.content
    def call_back(obj):
        print('->>>>>>>>>call_back , tid:',threading.currentThread().ident, ',obj:',obj)
     
    with futures.ThreadPoolExecutor(max_workers=3) as ex:
        # mp = {ex.submit(load_url,url) : url for url in URLS}
        mp = dict()
        for url in URLS:
            f = ex.submit(load_url,url)
            mp[f] = url
            f.add_done_callback(call_back)
        for f in futures.as_completed(mp):
            url = mp[f]
            try:
                data = f.result()
            except Exception as exc:
                print(exc, ',url:',url)
            else:
                print('url:', url, ',len:',len(data),',data[:20]:',data[:20])
    """
    tid: 7128 ,url: http://baidu.com
    tid: 7892 ,url: http://www.qq.com
    tid: 3712 ,url: http://www.sina.com.cn
    ->>>>>>>>>call_back , tid: 7892 ,obj: <Future at 0x2dd64b0 state=finished returned bytes>
    url: http://www.qq.com ,len: 251215 ,data[:20]: b'<!DOCTYPE html>
    <htm'
    ->>>>>>>>>call_back , tid: 3712 ,obj: <Future at 0x2de07b0 state=finished returned bytes>
    url: http://www.sina.com.cn ,len: 577333 ,data[:20]: b'<!DOCTYPE html>
    <!--'
    ->>>>>>>>>call_back , tid: 7128 ,obj: <Future at 0x2d533d0 state=finished returned bytes>
    url: http://baidu.com ,len: 81 ,data[:20]: b'<html>
    <meta http-eq'
    """
  • 相关阅读:
    linux进程间通信-共享内存
    where和having子句的区别
    多进程和多线程的区别(转载)
    android手机调试时不能打印Logcat日志信息
    来源不清,随笔
    转载
    C语言和Lua的交互
    python常用代码笔记
    python入门问题(windows7+python35+pycharm)
    常用matlab代码笔记
  • 原文地址:https://www.cnblogs.com/shuai1991/p/11224919.html
Copyright © 2011-2022 走看看