• KaitoShy
    2019-06-26
    思考题:
    1. request.get 会触发:ConnectionError, TimeOut, HTTPError等,所有显示抛出的异常都是继承requests.exceptions.RequestException
    2. executor.map(download_one, urls) 会触发concurrent.futures.TimeoutError
    3. result() 会触发Timeout,CancelledError
    4. as_completed() 会触发TimeOutError

    作者回复: 回答的很对

     2
     26
  • SCAR
    2019-06-26
    future之与中文理解起来其实挺微妙,不过这与生活中大家熟知的期物在底层逻辑上是一致的,future英文词义中就有期货的意思,都是封存一个东西,平常你该干嘛就干嘛,可以不用去理会,在未来的某个时候去看结果就行,只是python中那个物是对象而已。而关键词是延迟,异步。
    思考题:添加异常处理
    def download_all(sites):
        with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
            to_do = {}
            for site in sites:
                future = executor.submit(download_one, site)
                to_do[future]=site
                
            for future in concurrent.futures.as_completed(to_do):
                try:
                    res=future.result()
                except request.exceptions.HTTPError as e:
                    e_msg=‘HTTP erro’
                except request.exceptions.ConnectionError as e:
                    e_msg=‘Connection erro’
                else:
                    e_msg=''
                if e_msg:
                    site=to_do[future]
                    Print(‘Error is {} from {}’.format(e_msg,site))
    展开
     1
     14
  • Luke Zhang
    2019-06-26
    关于concurrent写过一篇学习笔记:
    https://www.zhangqibot.com/post/python-concurrent-futures/
    Python实现多线程/多进程,大家常常会用到标准库中的threading和multiprocessing模块。
    但从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,实现了对threading和multiprocessing的进一步抽象,使得开发者只需编写少量代码即可让程序实现并行计算。
    
     9
  • Fergus
    2019-06-30
    需要加异常的应该就只有一个地方:requests.get()发送网页请求的时候。其它地方不涉及IO。也不涉及数据类型变化,不用做数据类型判断。
    由于不能访问wiki,所以网页改了成了国内的。
    -- ps: 和0.2s比起来太慢了。

    # -*- encoding -*-
    '''
    py 3.6
    sulime
    '''
    import concurrent.futures
    import threading
    import requests
    import time

    now = lambda: time.perf_counter()

    def download_one(url):
        try:
            req = requests.get(url)
            req.raise_for_status()
            print('Read {} from {}'.format(len(req.content), url))
        except:
            print('404')

    def download_all(sites):
        with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
            executor.map(download_one, sites)

    def main():
        sites = [
                'https://www.baidu.com/',
                'https://pypi.org/',
                'https://www.sina.com.cn/',
                'https://www.163.com/',
                'https://news.qq.com/',
                'http://www.ifeng.com/',
                'http://www.ce.cn/',
                'https://news.baidu.com/',
                'http://www.people.com.cn/',
                'http://www.ce.cn/',
                'https://news.163.com/',
                'http://news.sohu.com/'
                ]
        start = now()
        download_all(sites)
        print('Download {} sites in {} s'.format(len(sites), now() - start))

    if __name__ == '__main__':
        main()

    # Read 2443 from https://www.baidu.com/
    # Read 6216 from https://news.qq.com/
    # Read 699004 from https://www.163.com/
    # Read 250164 from http://www.ifeng.com/
    # Read 579572 from https://www.sina.com.cn/
    # Read 107530 from http://www.ce.cn/
    # Read 165901 from http://www.people.com.cn/
    # Read 107530 from http://www.ce.cn/
    # Read 210816 from https://news.163.com/
    # Read 74060 from https://news.baidu.com/
    # Read 174553 from http://news.sohu.com/
    # Read 19492 from https://pypi.org/
    # Download 12 sites in 2.8500169346527673 s
    # [Finished in 3.6s]
    展开
    
     4
  • 大王叫我来巡山
    2019-11-19
    老师,我感觉您对并发和并行的理解是有问题的,并发是针对最初的单核CPU的,并行是针对现代的多核CPU,并且所有的调度行为都是基于线程的,一个进程中至少有一个线程,资源的分配是基与进程的,并不是只有多进程模型才可以同时在多个核心上运行的。
     2
     3
  • Geek_5bb182
    2019-06-27
    老师你好,concurrent.futures 和 asyncio 中的Future 的区别是什么,在携程编程中

    作者回复: 可以参考https://stackoverflow.com/questions/29902908/what-is-the-difference-between-concurrent-futures-and-asyncio-futures

    
     3
  • somenzz
    2019-07-19
    from multiprocessing.dummy import Pool as ThreadPool
    with ThreadPool(processes=100) as executor:
        executor.map(func, iterable)

    请问老师,Futures 和这种方式哪一种好呢? 我在实际的网终请求中发现 Futures 请求成功的次数更少。 都是 100 个线程,处理 3000 个相同的请求。
    
     2
  • Fergus
    2019-06-30
    老师好,看到文中为了使用.as_complete()作的修改似乎做了重复的工作,我对比了使用.as_complete()和.submit()后直接result(),得到的是相同的结果。
    -- 问1:这里所做的修改只是为了展示.as_complete的功能么?我查看了文档也没想明白。
    -- 问2:.as_complete()可能会在什么场景下使用得比较多?

    eg.2.`.submit()`后直接`.result()`
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
            for site in sites:
                future = executor.submit(download_one, site)
                print(future.result())
    展开
     1
     2
  • 悟空
    2020-01-09
    学习到的知识点:
    1. 并发和并行的区别,大佬通俗易懂的方式让我更深刻的体会到了程序到底是如何跑在多核机器上的
    2. python中 Futures 特性,第一次接触到这个模块,待后续继续加深了解;
    3. Python 中之所以同一时刻只允许一个线程运行,大佬解释了这是因为全局解释器锁的存在,而全局解释器锁又是为了解决 race condition而引入的,这个也从另一方面验证了我之前学习到的,python中多线程是无法利用多核的;
    但是多线程无法利用多核也并不是一无是处,就像大佬在文中聊到的,多线程主要的适用场景就是 有IO延迟的场景,因为一个线程遇到IO延迟,它占用的全局解释器锁就会释放,而另一个线程即可以拿到锁开始执行; 这种在IO延迟场景中的并发,高效也是显而易见的;
    展开

    作者回复: 说的很对

    
     1
  • 羁绊
    2019-06-30
    在使用executor.map()时候假如上面sites里面的url有链接超时报错的话,ThreadPoolExecutor会隐藏该异常,这个线程会在没有任何输出的情况下终止,然后线程继续执行
    
     1
  • 干布球
    2019-06-26
    请问老师,future任务是调用submit后就开始执行,还是在调用as_completed之后才开始执行呢?

    作者回复: submit之后

     2
     1
  • 无才不肖生
    2019-06-26
    在submit()后只是放入队列而并未真正开始执行,as_completed时才真正去执行,对吗?
    as_completed会不会有个别future并执行完而没有输出结果,还是说就一定都会完成
    
     1
  • beiler
    2020-01-01
    如果线程是遇到I/O就切换,那和协程有什么区别呢?
    
    
  • Paul Shan
    2019-11-21
    请问老师,多数编程语言的并行(Parallelism),都是通过多线程实现(例如rxjava),因为线程是CPU调度的最小单元,为什么Python并行是通过多进程实现,多谢!
    
    
  • Paul Shan
    2019-11-20
    Future 是一个任务队列模型,所有需要IO的任务,都进入队列,然后根据IO和CPU的使用来回调度任务,合理配置IO和CPU的资源。
    
    
  • Paul Shan
    2019-11-20
    Concurrency -- 流水线,充分利用不同的设备,例如CPU,内存和网络,同一时刻,只有一个任务被CPU执行。
    Parallelism -- 并行处理,充分利用多个CPU
    多进程不会比多线程块,我个人以为线程是操作系统调度的最小单元,切换进程比切换线程代价大。
    
    
  • Leon📷
    2019-11-10
    老师给一些不存在的网站让我们去测试用例,机智的我换成了BAT的首页
    
    
  • tsunami
    2019-10-14
    老师,python不是不适合多线程吗,多线程由于GIL反而变慢了吗,这个只是针对cpu密集型的不适合多线程吗,IO密集型的可以使用python多线程吗?
    
    
  • 自由民
    2019-10-12
    并发是交替执行,同时只有一个任务执行。用于高I/O程序。并行是多个进程同时运行,用于CPU-heavy程序。原来Python可以做并行运算的,建立线程池的时候不指定线程数量就行了。以前写并发程序比较少。
    思考题,只写异常处理的地方吧。
    # 处理requests异常
        except ConnectionError as err:
            print(err)
        except HTTPError as err:
            print(err)
        except Timeout as err:
            print(err)
        # 处理futures异常
        except TooManyRedirects as err:
            print(err)
        except CancelledError as err:
            print(err)
        except TimeoutError as err:
            print(err)
        except BrokenExecutor as err:
            print(err)
        except:
            print("发生错误")

    课程的练习代码: https://github.com/zwdnet/PythonPractice
    展开
    
    
  • 建强
    2019-10-11
    简单的加了个异常处理,请老师指正
    #多线程实现网站内容下载演示
    import concurrent.futures
    import requests
    import threading
    import time

    def download_one(url):
        resp = requests.get(url)
        print('Read {} from {}'.format(len(resp.content), url))
        
        #模拟下载任务出错
        print(1/0)

    def download_all(sites):
        try:
            #以下是用futures对象并发下载
            with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
                to_do = []
                for site in sites:
                    future = executor.submit(download_one, site)
                    to_do.append(future)

                for future in concurrent.futures.as_completed(to_do):
                    future.result()
                        
        except Exception as e:
            print('运行错误:',e)
    展开
    
    
我们在线,来聊聊吧