精华内容
下载资源
问答
  • python线程池和进程池

    2021-01-20 16:19:26
    线程池和进程池 开局来张图 使用线程池的好处 1.提升性能:因为减去了大量新建、终止线程的开销,重用了线程资源 2.使用场景:适合处理突发性大量请求或需要大量线程完成任务、但实际任务处理时间较短 3.防御功能...

    线程池和进程池

    开局来张图

    在这里插入图片描述

    • 使用线程池的好处

      1.提升性能:因为减去了大量新建、终止线程的开销,重用了线程资源

      2.使用场景:适合处理突发性大量请求或需要大量线程完成任务、但实际任务处理时间较短

      3.防御功能:能有效避免系统因为创建线程过多,而导致系统负荷过大相应变慢等问题

      4.代码优势:使用线程池的语法比自己新建线程执行线程更加简洁

    concurrent.futures进行并发编程

    concurrent.futures模块对threading和multiprocessing模块进行了进一步的包装,可以很方便地实现池的功能

    concurrent.futures提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,都继承自Executor,分别被用来创建线程池和进程池,接收max_workers参数,代表创建的线程数或者进程数。ProcessPoolExecutor的max_workers参数可以为空,程序会自动创建基于电脑cpu数据的进程数。

    • submit
     from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
      import requests
    
        def load_url(url):
            return requests.get(url)
    
        url = 'http://httpbin.org'
        executor = ThreadPoolExecutor(max_workers=1)
        future = executor.submit(load_url, url)
    

    Executor中定义了submit()方法,这个方法的作用是提交一个可执行的回调task,返回一个future实例。future能够使用done()方法判断该任务是否结束,done()方法是不阻塞的,使用result()方法可以获取任务的返回值,这个方法是阻塞的。

    	print future.done()
        print future.result().status_code
    

    submit()方法只能进行单个任务,用并发多个任务,需要使用mao与as_completed

    • map
      URLS = ['http://httpbin.org', 'http://example.com/', 'https://api.github.com/']
       
      def load_url(url):
          return requests.get(url)
       
      with ThreadPoolExecutor(max_workers=3) as executor:
          for url, data in zip(URLS, executor.map(load_url, URLS)):
              print('%r page status_code %s' % (url, data.status_code))
      

      结果:

      'http://httpbin.org'` `page status_code ``200``'http://example.com/'` `page status_code ``200``'https://api.github.com/'` `page status_code ``200
      

    map方法接收两个参数,第一个是要执行的函数,第二个为一个序列,会对序列中的每个元素执行这个函数。

    • as_completed

      as_completed()方法返回一个Future组成的生成器,在没有任务完成的时候,会阻塞,在有某个任务完成的时候,会yield这个任务,直到所有的任务结束。

      def load_url(url):
          return url, requests.get(url).status_code
       
      with ThreadPoolExecutor(max_workers=3) as executor:
          tasks = [executor.submit(load_url, url) for url in URLS]
          for future in as_completed(tasks):
              print future.result()
      

      结果:

      ('http://example.com/', 200)
      ('http://httpbin.org', 200)
      ('https://api.github.com/', 200)
      

      可以看出,结果与序列顺序不一致,先完成的任务会先通知主线程

    • wait

      wait方法可以让主线程阻塞,直到满足设定的要求。有三种条件有三种条件ALL_COMPLETED, FIRST_COMPLETED,FIRST_EXCEPTION。

    • from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, wait, ALL_COMPLETED, FIRST_COMPLETED
      from concurrent.futures import as_completed
      import requests
       
      URLS = ['http://httpbin.org', 'http://example.com/', 'https://api.github.com/']
       
      def load_url(url):
          requests.get(url)
          print url
       
      with ThreadPoolExecutor(max_workers=3) as executor:
          tasks = [executor.submit(load_url, url) for url in URLS]
          wait(tasks, return_when=ALL_COMPLETED)
          print 'all_cone'
      

      返回:
      http://example.com/
      http://httpbin.org
      https://api.github.com/
      all_cone
      可以看出阻塞到任务全部完成。

    ProcessPoolExecutor

    使用ProcessPoolExecutor与ThreadPoolExecutor方法基本一致

    展开全文
  • from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor import ... 在开启多进程时候,必须要指定主程序__name__ == ‘main’ 使用map是顺序输出,要想不顺序输出,可以使用as_completed 图片来源
    from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
    import time
    def calctime(x):
        start = time.perf_counter()
        x()
        end = time.perf_counter()
        return("time cost is", end-start)
    def fun(x):
        a, b = x
        time.delay(2)
        return('a is ', a, 'b is ', b)
    def muti_thread1():
        with ThreadPoolExecutor() as pool:
            data = [(x, x) for x in range(50)]
            results = pool.map(fun, data)
    def thread():
        data = [(x, x) for x in range(50)]
        for i in data:
            fun(i)
    def muti_process():
        with ProcessPoolExecutor() as pool:
            data = [(x, x) for x in range(50)]
            results = pool.map(fun, data)
    if __name__ == '__main__':
        print(calctime(muti_thread1))
        print(calctime(thread))
        print(calctime(muti_process))
    

    在这里插入图片描述

    注意事项:

    1. 要注意在开启线程的程序中,一定要注意变量的使用是否是赋值、浅拷贝、还是深拷贝,则会影响到线程之间的变量共享使用等!
    2. 在开启多进程时候,必须要指定主程序__name__ == ‘main
    3. 使用map是顺序输出,要想不顺序输出,可以使用as_completed
      在这里插入图片描述
      图片来源
    展开全文
  • 进程池 协程 try异常处理 IO多路复用 线程的继承调用 1.线程池 线程池帮助你来管理线程,不再需要每个任务都创建一个线程进行处理任务。 任务需要执行时,会从线程池申请线程,有则使用线程池...

    本节内容

    1. 线程池

    2. 进程池
    3. 协程

    4. try异常处理

    5. IO多路复用

    6. 线程的继承调用

    1.线程池

    线程池帮助你来管理线程,不再需要每个任务都创建一个线程进行处理任务。

    任务需要执行时,会从线程池申请线程,有则使用线程池的线程执行任务,如果没有就等着,其他在执行的任务执行完毕后释放线程,等待的任务就可以使用释放的线程来执行操作了。

    from concurrent.futures import ThreadPoolExecutor
    import requests
    import time
    def taks(url):  # 线程的回调函数,处理消息
        time.sleep(1)
        response = requests.get(url)
        print(response.url,response.status_code)
    pool = ThreadPoolExecutor(2)  # 线程池中有两个线程轮流工作
    url_list = [
        'http://www.baidu.com',  # 数据是了看清楚程序是同时执行两个。
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
    ]
    for url in url_list:
        # 去线程池中去线程工作
        pool.submit(taks,url)  
    

    2.进程池

    进程池和线程池在我看来其实是差不多的。

    下面使用进程池来实现和上面同样的效果。

    from concurrent.futures import ProcessPoolExecutor
    import time
    import requests 
    def task(url):
        time.sleep(1)
        response = requests.get(url)
        print(response.url,response.status_code)
    pool = ProcessPoolExecutor(2)  # 定义进程池
    url_list = [
        'http://www.baidu.com',  # 数据是了看清楚程序是同时执行两个。
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
        'http://www.baidu.com',
    ]
    if __name__ == '__main__':
        for url in url_list:
            pool.submit(task,url)
    

    进程池回调函数的使用:

    # pip3 install requests
    from concurrent.futures import ThreadPoolExecutor
    import requests
    import time
    def txt(futer):  # 负责处理数据
        down_txt = futer.result()
        print("处理后的信息:",down_txt.url,down_txt.status_code)
    
    def down(url):# 负责下载
        print('开始请求:', url)
        response = requests.get(url)
        return response
    
    pool = ThreadPoolExecutor(2)
    url_list=[
        'http://www.sina.com.cn',
        'http://www.autohome.com.cn',
        'http://www.oldboyedu.com',
        'http://www.qq.com',
        'http://www.taobao.com',
        'http://www.baidu.com',
    ]
    for url in url_list:
        futer = pool.submit(down,url)
        futer.add_done_callback(txt)
    

    3.协程

    线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

    协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

    协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;

    协程的好处:

    • 无需线程上下文切换的开销
    • 无需原子操作锁定及同步的开销
      • "原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。
    • 方便切换控制流,简化编程模型
      • 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

    缺点:

    • 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
    • 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

    我们先给协程一个标准定义,即符合什么条件就能称之为协程:

    1. 必须在只有一个单线程里实现并发
    2. 修改共享数据不需加锁
    3. 用户程序里自己保存多个控制流的上下文栈
    4. 一个协程遇到IO操作自动切换到其它协程

    3.1 greenlet

    greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator

    from greenlet import greenlet
     
     
    def test1():
        print(12)
        gr2.switch()
        print(34)
        gr2.switch()
     
     
    def test2():
        print(56)
        gr1.switch()
        print(78)
     
     
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    gr1.switch()
    greenlet

    3.2 gevent 

    Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

    import gevent
    def task(pid):
        gevent.sleep(0.5)
        print('Task %s done' % pid)
    def synchronous():
        for i in range(1, 10):
            task(i)
    def asynchronous():
        threads = [gevent.spawn(task, i) for i in range(10)]
        gevent.joinall(threads)
    print('Synchronous:')
    synchronous()
    print('Asynchronous:')
    asynchronous()
    

    上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn。 初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数,后者阻塞当前流程,并执行所有给定的greenlet。执行流程只会在 所有greenlet执行完后才会继续向下走。

    遇到IO阻塞时会自动切换任务

    import gevent
    import requests
    def func(url):
        response = requests.get(url)
        print(response.url,response.status_code)
    
    gevent.joinall([
            gevent.spawn(func, 'http://www.oldboyedu.com/'),
            gevent.spawn(func, 'http://www.baidu.com/'),
            gevent.spawn(func, 'http://autohome.com/'),
    ]) 

    协程的详细使用:

    http://www.cnblogs.com/aylin/p/5601969.html

    http://www.cnblogs.com/alex3714/articles/5248247.html

    4. try异常处理

    异常处理的注意事项
      缩进错误和语法错误无法捕捉到。
        IndentationError:缩进错误
        SyntaxError:语法错误
      Exception 相当于 BaseException 都是万能异常

    try:
        print(name)
    except NameError as e:
        print(e)
    else:
        print("如果什么错误也没有会执行else下的代码")
    finally:
        print("无论有没有错都执行finally下的代码")
    
    # 输出
    # name 'name' is not defined
    # 无论有没有错都执行finally下的代码

    1.name变量不存在,捕捉NameErrot异常,打印异常信息

    try:
        print(name)
    except NameError as e:
        print(e)

    2.抓多个异常(只能抓一个)

    try:
        name=[1,2,3]
        print(names)
        print(name[4])
    except NameError as e:
        print(e)
    except IndexError as e:
        print(e)

    3.抓多个异常(一次也只能抓到一个异常)

    try:
        name=[1,2,3]
        print(names)
        print(name[4])
    except (NameError,IndexError) as e:
        print(e)

    4.万能异常(Exception)

    try:
        name=[1,2,3]
        print(names)
        print(name[4])
    except Exception as e:
        print(e)

    5.异常用法

    try:
        pass
    except NameError as e:
        print(e)
    except IndexError as e:
        print(e)
    except Exception as e:
        print(e)

    6.自定义异常

    class helei(Exception): # 继承 Exception
        def __init__(self,msg):
            self.message = msg
        # def __str__(self):  #被print调用时执行,可以不写
        #     return self.message
    try:
        raise helei('我的异常') # 触发异常
    except helei as e:
      print(e)

    5.IO多路复用

    I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

    select
     
    select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。
    select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。
    select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。
    另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。
     
    poll
     
    poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。
    poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
    另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。
     
    epoll
     
    直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。
    epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
    epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。
    另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。
    select,poll,epoll

    Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。

    Windows Python:
        提供: select
    Mac Python:
        提供: select
    Linux Python:
        提供: select、poll、epoll
    

    注意:网络操作、文件操作、终端操作等均属于IO操作,对于windows只支持Socket操作,其他系统支持其他IO操作,但是无法检测 普通文件操作 自动上次读取是否已经变化。

    对于select方法:

    句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间)
     
    参数: 可接受四个参数(前三个必须)
    返回值:三个列表
     
    select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。
    1、当 参数1 序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值1 序列中
    2、当 参数2 序列中含有句柄时,则将该序列中所有的句柄添加到 返回值2 序列中
    3、当 参数3 序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值3 序列中
    4、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化
       当 超时时间 = 1时,那么如果监听的句柄均无任何变化,则select会阻塞 1 秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。
    select
    import socket
    import select
    
    sk1 = socket.socket()
    sk1.bind(('127.0.0.1',8001))
    sk1.listen(5)
    
    sk2 = socket.socket()
    sk2.bind(('127.0.0.1',8002))
    sk2.listen(5)
    inputs = [sk1,sk2]
    while True:
        r, w, e = select.select(inputs, [], [], 5)
        for obj in r:
            if obj in [sk1,sk2]:
                print('新连接来了。。')
                conn,addr = obj.accept()
                inputs.append(conn)
            else:
                print('有用户发消息来了。。')
                data = obj.recv(1024)
                obj.sendall(data)
    利用select实现伪同时监听多个服务端
    import socket
    import select
    client = socket.socket()
    client.connect(('127.0.0.1', 8001,))
    while True:
        # v = input('>>>')
        # client.sendall(bytes(v,encoding='utf-8'))
        # ret = client.recv(1024)
        # print('服务器返回:',ret)
        read_list = [client]
        write_list = []
        # print('select')
        for obj in read_list:
            if obj:
                data = input(":>>")
                obj.send(data.encode())
                read_list.remove(obj)
                write_list.append(obj)
            else:
                pass
        r, w, e = select.select(read_list, write_list, read_list)
        # print('r',r)
        # print('w',w)
        for obj in write_list:
            data = obj.recv(1024)
            print(data)
    客户端-1(基于select实现)好像有错
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1',8002,))
    
    while True:
        v = input('>>>')
        client.sendall(bytes(v,encoding='utf-8'))
        ret = client.recv(1024)
        print('服务器返回:',ret)
    客户端-2

    抄袭地址:http://www.cnblogs.com/wupeiqi/articles/5040823.html

    select,poll,epoll详细看这里:

    http://www.cnblogs.com/alex3714/p/4372426.html

    https://segmentfault.com/a/1190000003063859

    https://my.oschina.net/moooofly/blog/147297

    6. 线程的继承调用

    忘了,下次补。

     

     

     

    adfsaf

    转载于:https://www.cnblogs.com/40kuai/p/6640359.html

    展开全文
  • 主要介绍了python爬虫之线程池和进程池功能与用法,结合实例形式分析了Python基于线程池与进程池的爬虫功能相关操作技巧与使用注意事项,需要的朋友可以参考下
  • 原文来自开源中国前言python标准库提供线程多处理模块来编写相应的多线程/多进程代码,但当项目达到一定规模时,频繁地创建/销毁进程或线程是非常消耗资源的,此时我们必须编写自己的线程池/进程池来交换时间空间...

    原文来自开源中国

    前言

    python标准库提供线程和多处理模块来编写相应的多线程/多进程代码,但当项目达到一定规模时,频繁地创建/销毁进程或线程是非常消耗资源的,此时我们必须编写自己的线程池/进程池来交换时间空间。但是从Python3.2开始,标准库为我们提供了并发的。Futures模块,它提供两个类:ThreadPool Executor和ProcessPool Executor。它实现线程和多处理的进一步抽象,并为编写线程池/进程池提供直接支持。

    Executor和Future

    concurrent.futures模块的基础是Exectuor,Executor是一个抽象类,它不能被直接使用。但是它提供的两个子类ThreadPoolExecutor和ProcessPoolExecutor却是非常有用,顾名思义两者分别被用来创建线程池和进程池的代码。我们可以将相应的tasks直接放入线程池/进程池,不需要维护Queue来操心死锁的问题,线程池/进程池会自动帮我们调度。

    使用submit来操作线程池/进程池

    我们先通过下面这段代码来了解一下线程池的概念

    # example1.pyfrom concurrent.futures import ThreadPoolExecutorimport timedef return_future_result(message):

    time.sleep(2) return message

    pool = ThreadPoolExecutor(max_workers=2) # 创建一个最大可容纳2个task的线程池future1 = pool.submit(return_future_result, ("hello")) # 往线程池里面加入一个taskfuture2 = pool.submit(return_future_result, ("world")) # 往线程池里面加入一个taskprint(future1.done()) # 判断task1是否结束time.sleep(3)

    print(future2.done()) # 判断task2是否结束print(future1.result()) # 查看task1返回的结果print(future2.result()) # 查看task2返回的结果

    让我们根据操作结果进行分析。我们使用submit方法将任务添加到线程池,submit返回一个将来的对象,这可以简单地理解为将来要完成的操作。在第一份印刷声明中,很明显我们的未来1由于时间的原因没有完成。睡眠(2),因为我们使用时间挂起了主线程。sleep(3),所以到第二个print语句时,线程池中的所有任务都已完成。

    ziwenxie :: ~ » python example1.pyFalseTruehello

    world# 在上述程序执行的过程中,通过ps命令我们可以看到三个线程同时在后台运行ziwenxie :: ~ » ps -eLf | grep python

    ziwenxie 8361 7557 8361 3 3 19:45 pts/0 00:00:00 python example1.py

    ziwenxie 8361 7557 8362 0 3 19:45 pts/0 00:00:00 python example1.py

    ziwenxie 8361 7557 8363 0 3 19:45 pts/0 00:00:00 python example1.py

    上面的代码我们也可以改写为进程池形式,api和线程池如出一辙,我就不罗嗦了。

    # example2.pyfrom concurrent.futures import ProcessPoolExecutorimport timedef return_future_result(message):

    time.sleep(2) return message

    pool = ProcessPoolExecutor(max_workers=2)

    future1 = pool.submit(return_future_result, ("hello"))

    future2 = pool.submit(return_future_result, ("world"))

    print(future1.done())

    time.sleep(3)

    print(future2.done())

    print(future1.result())

    print(future2.result())

    下面是运行结果

    ziwenxie :: ~ » python example2.pyFalseTruehello

    world

    ziwenxie :: ~ » ps -eLf | grep python

    ziwenxie 8560 7557 8560 3 3 19:53 pts/0 00:00:00 python example2.py

    ziwenxie 8560 7557 8563 0 3 19:53 pts/0 00:00:00 python example2.py

    ziwenxie 8560 7557 8564 0 3 19:53 pts/0 00:00:00 python example2.py

    ziwenxie 8561 8560 8561 0 1 19:53 pts/0 00:00:00 python example2.py

    ziwenxie 8562 8560 8562 0 1 19:53 pts/0 00:00:00 python example2.py

    使用map/wait来操作线程池/进程池

    除了submit,Exectuor还为我们提供了map方法,和内建的map用法类似,下面我们通过两个例子来比较一下两者的区别。

    使用submit操作回顾

    # example3.pyimport concurrent.futuresimport urllib.request

    URLS = ["http://httpbin.org", "http://example.com/", "https://api.github.com/"]def load_url(url, timeout):

    with urllib.request.urlopen(url, timeout=timeout) as conn: return conn.read()# We can use a with statement to ensure threads are cleaned up promptlywith concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: # Start the load operations and mark each future with its URL

    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS} for future in concurrent.futures.as_completed(future_to_url):

    url = future_to_url[future] try:

    data = future.result() except Exception as exc:

    print("%r generated an exception: %s" % (url, exc)) else:

    print("%r page is %d bytes" % (url, len(data)))

    从运行结果可以看出,as_completed不是按照URLS列表元素的顺序返回的。

    ziwenxie :: ~ » python example3.py"http://example.com/" page is 1270 byte"https://api.github.com/" page is 2039 bytes"http://httpbin.org" page is 12150 bytes

    使用map

    # example4.pyimport concurrent.futuresimport urllib.request

    URLS = ["http://httpbin.org", "http://example.com/", "https://api.github.com/"]def load_url(url):

    with urllib.request.urlopen(url, timeout=60) as conn: return conn.read()# We can use a with statement to ensure threads are cleaned up promptlywith concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: for url, data in zip(URLS, executor.map(load_url, URLS)):

    print("%r page is %d bytes" % (url, len(data)))

    从运行结果可以看出,map是按照URLS列表元素的顺序返回的,并且写出的代码更加简洁直观,我们可以根据具体的需求任选一种。

    ziwenxie :: ~ » python example4.py"http://httpbin.org" page is 12150 bytes"http://example.com/" page is 1270 bytes"https://api.github.com/" page is 2039 bytes

    第三种选择wait

    wait方法接会返回一个tuple(元组),tuple中包含两个set(集合),一个是completed(已完成的)另外一个是uncompleted(未完成的)。使用wait方法的一个优势就是获得更大的自由度,它接收三个参数FIRST_COMPLETED, FIRST_EXCEPTION 和ALL_COMPLETE,默认设置为ALL_COMPLETED。

    我们通过下面这个例子来看一下三个参数的区别

    from concurrent.futures import ThreadPoolExecutor, wait, as_completedfrom time import sleepfrom random import randintdef return_after_random_secs(num):

    sleep(randint(1, 5)) return "Return of {}".format(num)

    pool = ThreadPoolExecutor(5)

    futures = []for x in range(5):

    futures.append(pool.submit(return_after_random_secs, x))

    print(wait(futures))# print(wait(futures, timeout=None, return_when="FIRST_COMPLETED"))

    如果采用默认的ALL_COMPLETED,程序会阻塞直到线程池里面的所有任务都完成。

    ziwenxie :: ~ » python example5.py

    DoneAndNotDoneFutures(done={,,,,}, not_done=set())

    如果采用FIRST_COMPLETED参数,程序并不会等到线程池里面所有的任务都完成。

    ziwenxie :: ~ » python example5.py

    DoneAndNotDoneFutures(done={,,},

    not_done={,})

    展开全文
  • #python自带的线程池 from multiprocessing.pool import ThreadPool #注意ThreadPool不...from multiprocessing import Pool #导入进程池 def func(*args,**kwargs): print(args,kwargs) pool=ThreadPool(2) #poo...
  • 学习python3中线程池的用法鱼进程池的用法 一、python3线程的基本用法 Python中使用线程有两种方式:函数或者用类来包装线程对象 1.1 函数调用方法 thread.start_new_thread ( function, args[, kwargs] ) 参数...
  • 1、线程池ThreadPoolExecutor """ 线程池,使用单核CPU """ from concurrent.futures import ThreadPoolExecutor import random import time import threading from datetime import datetime import ...
  • 1、线程池的内部实现可以先看...下面是代码示例注释 #coding='utf-8' #threadpool.ThreadPool,线程池类 import os import time import threadpool def print_file_head(filename): print("begin r...
  • Python中的concurrent并发包(构建线程池和进程池) 文章目录Python中的concurrent并发包(构建线程池和进程池)ThreadPoolExecutor线程池与ProcessPoolExecutor进程池对象构造方法concurrent.futures.Future类,未来...
  •  上面我们介绍了多线程(线程池),现在我们聊聊进程池,我们知道一个进程占用一个CPU,现在的配置CPU一般都是4核,我们启动两个进程就是分别在两个CPU里面(两个内核)各运行一个进程,我知道进程里面才有线程,...
  • 文章目录 一般我们是通过动态创建子进程(或子线程)来实现并发服务器的,但是会存在这样一些缺点: 1、动态创建进程(或线程)比较耗费时间,这将导致较慢的服务器响应。... 所以呢,就引入了进程池
  • import time from multiprocessing.pool import ThreadPool #注意ThreadPool不在threading...from multiprocessing import Pool #导入进程池 def my_print(i): print("task start {}".format(i)) time.sleep(4) ...
  • 线程池和进程池模块: from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor Python2版本: 线程池:不支持 进程池:支持 Python3版本: 线程池:支持 进程池:支持 ...
  • ####一、需求 最近准备爬取某电商网站的数据,先不考虑代理、分布式,先说效率问题(当然你...确定要用多线程或者多进程了,那我们到底是用多线程还是多进程,有些人对多进程和多线程有一定的偏见,就因为python的GIL
  • concurrent.futrues是个高级的的库,它只在“任务”级别进行操作,意思是你不需要关注同步线程、...你只需要指定一个“max_workers”数量的线程/进程池,然后提交任务整理结果即可,另一个好处是相对于threading...
  • 我们都知道,不管是Java,还是C++,还是Go,还是Python,都是有线程这个概念的。 但是我们知道,线程是不能随便创建的,就像每招一个员工一样,是有代价的,无限制招人肯定最后各种崩溃。 所以通常情况下,我们会...

空空如也

空空如也

1 2 3 4 5 ... 15
收藏数 284
精华内容 113
关键字:

python线程池和进程池

python 订阅