资讯专栏INFORMATION COLUMN

经验拾忆(纯手工)=> Python三程

Snailclimb / 2771人阅读

摘要:多线程对于爬虫方面也可以表现出较好的性能。计算密集型就别想多线程了,一律多进程。所以同一时刻最大的并行线程数进程数的核数这条我的个人理解很模糊,参考吧多线程多线程有种通过的那种方式,非常普遍,此处就不写了。

GIL的理解
GIL这个话题至今也是个争议较多的,对于不用应用场景对线程的需求也就不同,说下我听过的优点:
1. 我没有用过其他语言的多线程,所以无法比较什么,但是对于I/O而言,Python的线程还是比较高效的。
2. 有些第三方基于Python的框架和库,比如Tensorflow等基于C/C plus plus重写的Python线程机制。
3. 至于换成Cython编译器解决GIL,这个只是听过,没用过。
4. Python多线程对于web、爬虫方面也可以表现出较好的性能。
5. Python多进程是完好的,可以把资源消耗较少的非必要线程工作转为多进程来工作。
6. 计算密集型就别想多线程了,一律多进程。
7. Python还有细粒度且高效的协程。
8. 如果有N核CPU,那么同时并行的进程数就是N,每个进程里面只有一个线程能抢到工作权限。
   所以同一时刻最大的并行线程数=进程数=CPU的核数(这条我的个人理解很模糊,参考吧)
多线程
多线程有2种通过start的那种方式,非常普遍,此处就不写了。
新版线程池 future库 是python3.2新出的功能(记住这个future)
方式1:(sublime运行后直接贴上来了)
    from time import sleep
    from concurrent.futures import ThreadPoolExecutor,as_completed,ALL_COMPLETED,wait
    
    executor = ThreadPoolExecutor(max_workers=10)        # 初始化线程池10个坑
    def f():
        sleep(15)
        return 100
    all_tasks = [executor.submit(f) for _ in range(10)]  # 提交10个线程,全放池里执行
    # for per_thread in as_completed(all_tasks):         
        # print(per_thread.result())
    ---------# 注意上面,as_completed(all_tasks) 是等待future对象完成后才执行主线程
    ---------# 注意下面,wait和 as_completed() 的 作用一样,就和普通版的join() 相似
    for per_thread in all_tasks:
        print(per_thread.result())
    wait(all_tasks, return_when=ALL_COMPLETED)   # 还可以选FIRST_COMPLETED,待第一个完成后
    print("主线程")
        
方式2: map多线程版
    value_list = executor.map(func, list(range(10))) # 返回的直接是map后的序列
    for value in value_list:
        print(value)
    注意:    
        这个map方式,如果要传多个参数就涉及到高阶函数那节讲的偏函数了。
多进程
多进程有2种通过start的那种方式+普通进程池,同样非常普遍,此处就不写了,自己百度一下。
新版进程池 同样是和上面用一样的future库,惊不惊喜。(可以看出好的程序要向着统一封装的方向优化)
也许你会惊讶,因为只把thread单词改为processing就是进程池版本了,就是这么简单!!!!!
from time import sleep
import multiprocessing
from concurrent.futures import ProcessPoolExecutor,as_completed,ALL_COMPLETED,wait
executor = ProcessPoolExecutor(max_workers=multiprocessing.cpu_count())
def f():
    sleep(15)
    return 100

if __name__ == "__main__":    # 这句要加
    all_tasks = [executor.submit(f) for _ in range(multiprocessing.cpu_count())]
    for per_thread in as_completed(all_tasks):
        print(per_thread.result())
    # for per_thread in all_tasks:
    #     print(per_thread.result())
    # wait(all_tasks, return_when=ALL_COMPLETED)
    print("主进程")   
# 这就是 futures 模块 设计思想的魅力
多协程
前言:
    也许你记得,函数用到 yield 来代替 return 就变成了 生成器。其特点是代码片段断点式执行。
    如果有多个yield, 就可以自己用程序来切换执行程序。(这就是协程的特点)
推荐:(学习中。。。)
    此笔者写的很好:
    https://juejin.im/post/5ccf0d18e51d453b557dc340
    
    

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43848.html

相关文章

  • 经验拾忆手工)=> Python高阶函数操作

    摘要:解释就相当于把每个序列元素的每一个单独用一个管道函数处理,再把他们按顺序组合成一个新可迭代对象注意这个管道函数只能是单参数函数,如果想传递多个参数怎么办使用偏函数怕有些人看不懂,这里就不用了,而是用普通函数定义方式固定值固定值固定值固定值固 map In [25]: list(map(lambda a:a**2, [1,2,3,4])) Out[25]: [1, 4, 9, 16] 解...

    Elle 评论0 收藏0
  • 经验拾忆手工)=> Python基本数据类型

    摘要:不要疑惑,告诉你答案这个代表正负号的正。虽然一点技术含量没有,但是你要懂序列也许叫可迭代对象更为合适,但是我喜欢叫序列。 数据结构 可变类型与不可变类型(重头戏) 基操: 可变类型:[], {} # 可增删改 查 不可变类型: int float str () # 无法增删改, 只可查 升操: + 与...

    Andrman 评论0 收藏0
  • 经验拾忆手工)=> Python__黑魔法__

    摘要:类的继承类继承有三种调用方式,其实是有区别的,听我慢慢道来第一种父类方法参数直接调用第二种方法参数直接调用在谁的类下调用,就找此类对应的下一个就是要继承的第三种方法参数找类名对应的的下一个,就是继承的,一般写本身的类名上下文管理器上下文管理 类的继承 类继承有三种调用方式,其实是 有区别 的,听我慢慢道来 class A: def say(self, name): ...

    tulayang 评论0 收藏0
  • 经验拾忆手工)=> Python三器

    摘要:也就是给原函数加个外壳。类装饰填充了啊我是原函数类装饰填充了啊我是原函数说明后面关于类的装饰器如果理解困难当做了解即可,用的也少。 可迭代对象、生成器、迭代器三者的关系 1. 迭代器一定是可迭代对象 2. 生成器是迭代器的一种 3. 可迭代对象:必须实现 __iter__方法 4. 迭代器:必须实现 __iter__方法 和 __next__ 方法 5. 生成器:必须实现 __it...

    Miracle_lihb 评论0 收藏0
  • 经验拾忆手工)=> Python正则全解详解

    预编译 import re re1 = re.compile(r元字符 组成的正则规则) # 元字符下面会说 re1.方法() # 方法下边也会说 元字符: 表示普通字符: . # 除了 外 都可以匹配的到 d # 只匹配 纯数字 0-9 D # 和 d相反, 除了数字全都匹配 ...

    Luosunce 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<