? “Python猫” ,一个值得加星标的公众号

花下猫语:年关将近,不知各位过得怎样?我最近有些忙,收获也挺多,以后有机会分享下。吃饭时间,追了两部剧《了不起的麦瑟尔夫人》、《曼达洛人》,很喜欢这类风格的剧。想看剧的同学,不妨考虑下。回归正题,分享一篇文章。

作者:lgj_bky(经作者授权转载)

原文:https://www.cnblogs.com/lgjbky/p/10838035.html

剧照 | 《了不起的麦瑟尔夫人》

进程的定义:

进程,是计算机中已运行程序的实体。程序本身只是指令、数据及其组织形式的描述,进程才是程序的真正运行实例。

线程的定义:

操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

进程和线程的关系:

一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

CPU的最小调度单元是线程不是进程,所以单进程多线程也可以利用多核CPU.

协程的定义:

协程通过在线程中实现调度,避免了陷入内核级别的上下文切换造成的性能损失,进而突破了线程在IO上的性能瓶颈。

协程和线程的关系

协程是在语言层面实现对线程的调度,避免了内核级别的上下文消耗。

Python协程与调度

Python的协程源于yield指令。yield有两个功能:

  • yield item用于产出一个值,反馈给next()的调用方。
  • 作出让步,暂停执行生成器,让调用方继续工作,直到需要使用另一个值时再调用next()。
import asyncio

async def compute(x, y):    print("Compute %s + %s ..." % (x, y))    await asyncio.sleep(x + y)    return x + y

async def print_sum(x, y):    result = await compute(x, y)    print("%s + %s = %s" % (x, y, result))

loop = asyncio.get_event_loop()tasks = [print_sum(1, 2), print_sum(3, 4)]loop.run_until_complete(asyncio.wait(tasks))loop.close()

协程是对线程的调度,yield类似惰性求值方式可以视为一种流程控制工具,实现协作式多任务,在Python3.5正式引入了 async/await表达式,使得协程正式在语言层面得到支持和优化,大大简化之前的yield写法。

线程是内核进行抢占式的调度的,这样就确保了每个线程都有执行的机会。

而 coroutine 运行在同一个线程中,由语言的运行时中的 EventLoop(事件循环)来进行调度。

和大多数语言一样,在 Python 中,协程的调度是非抢占式的,也就是说一个协程必须主动让出执行机会,其他协程才有机会运行。

让出执行的关键字就是 await。也就是说一个协程如果阻塞了,持续不让出 CPU,那么整个线程就卡住了,没有任何并发。

PS: 作为服务端,event loop最核心的就是IO多路复用技术,所有来自客户端的请求都由IO多路复用函数来处理;作为客户端,event loop的核心在于利用Future对象延迟执行,并使用send函数激发协程,挂起,等待服务端处理完成返回后再调用CallBack函数继续下面的流程

Go的协程

Go天生在语言层面支持,和Python类似都是采用了关键字,而Go语言使用了go这个关键字,可能是想表明协程是Go语言中最重要的特性。

go协程之间的通信,Go采用了channel关键字。

Go实现了两种并发形式:

  • 多线程共享内存。如Java或者C++等在多线程中共享数据(例如数组、Map、或者某个结构体或对象)的时候,通过锁来访问.

  • Go语言特有的,也是Go语言推荐的:CSP(communicating sequential processes)并发模型。

Go的CSP并发模型实现:M, P, G : https://www.cnblogs.com/sunsky303/p/9115530.html

package main

import (    "fmt")

//Go 协程(goroutines)和协程(coroutines)//Go 协程意味着并行(或者可以以并行的方式部署),协程一般来说不是这样的//Go 协程通过通道来通信;协程通过让出和恢复操作来通信

// 进程退出时不会等待并发任务结束,可用通道(channel)阻塞,然后发出退出信号func main() {    jobs := make(chan int)    done := make(chan bool) // 结束标志

    go func() {        for {            j, more := //  利用more这个值来判断通道是否关闭,如果关闭了,那么more的值为false,并且通知给通道done            fmt.Println("----->:", j, more)            if more {                fmt.Println("received job", j)            } else {                fmt.Println("end received jobs")                done true                return            }        }    }()

    go func() {        for j := 1; j <= 3; j++ {            jobs             fmt.Println("sent job", j)        }        close(jobs) // 写完最后的数据,紧接着就close掉        fmt.Println("close(jobs)")    }()

    fmt.Println("sent all jobs")    // 让main等待全部协程完成工作}

通过在函数调用前使用关键字 go,我们即可让该函数以 goroutine 方式执行。goroutine 是一种 比线程更加轻盈、更省资源的协程。
Go 语言通过系统的线程来多路派遣这些函数的执行,使得 每个用 go 关键字执行的函数可以运行成为一个单位协程。
当一个协程阻塞的时候,调度器就会自 动把其他协程安排到另外的线程中去执行,从而实现了程序无等待并行化运行。
而且调度的开销非常小,一颗 CPU 调度的规模不下于每秒百万次,这使得我们能够创建大量的 goroutine,
从而可以很轻松地编写高并发程序,达到我们想要的目的。---- 某书

协程的4种状态

  • Pending

  • Running

  • Done

  • Cacelled

和系统线程之间的映射关系

go的协程本质上还是系统的线程调用,而Python中的协程是eventloop模型实现,所以虽然都叫协程,但并不是一个东西.

Python 中的协程是严格的 1:N 关系,也就是一个线程对应了多个协程。虽然可以实现异步I/O,但是不能有效利用多核(GIL)。

而 Go 中是 M:N 的关系,也就是 N 个协程会映射分配到 M 个线程上,这样带来了两点好处:

  • 多个线程能分配到不同核心上,CPU 密集的应用使用 goroutine 也会获得加速.

  • 即使有少量阻塞的操作,也只会阻塞某个 worker 线程,而不会把整个程序阻塞。

PS: Go中很少提及线程或进程,也就是因为上面的原因.

两种协程对比:

  • async是非抢占式的,一旦开始采用 async 函数,那么你整个程序都必须是 async 的,不然总会有阻塞的地方(一遇阻塞对于没有实现异步特性的库就无法主动让调度器调度其他协程了),也就是说 async 具有传染性。

  • Python 整个异步编程生态的问题,之前标准库和各种第三方库的阻塞性函数都不能用了,如:requests,redis.py,open 函数等。所以 Python3.5后加入协程的最大问题不是不好用,而是生态环境不好,历史包袱再次上演,动态语言基础上再加上多核之间的任务调度,应该是很难的技术吧,真心希望python4.0能优化或者放弃GIL锁,使用多核提升性能。

  • goroutine 是 go 与生俱来的特性,所以几乎所有库都是可以直接用的,避免了 Python 中需要把所有库重写一遍的问题。

  • goroutine 中不需要显式使用 await 交出控制权,但是 Go 也不会严格按照时间片去调度 goroutine,而是会在可能阻塞的地方插入调度。goroutine 的调度可以看做是半抢占式的。

PS: python异步库列表 https://github.com/timofurrer/awesome-asyncio


Do not communicate by sharing memory; instead, share memory by communicating.(不要以共享内存的方式来通信,相反,要通过通信来共享内存) -- CSP并发模型


扩展与总结

erlang和golang都是采用了CSP(Communicating Sequential Processes)模式(Python中的协程是eventloop模型)

但是erlang是基于进程的消息通信,go是基于goroutine和channel的通信。

Python和Go都引入了消息调度系统模型,来避免锁的影响和进程/线程开销大的问题。

协程从本质上来说是一种用户态的线程,不需要系统来执行抢占式调度,而是在语言层面实现线程的调度。

因为协程不再使用共享内存/数据,而是使用通信来共享内存/锁,因为在一个超级大系统里具有无数的锁,共享变量等等会使得整个系统变得无比的臃肿,而通过消息机制来交流,可以使得每个并发的单元都成为一个独立的个体,拥有自己的变量,单元之间变量并不共享,对于单元的输入输出只有消息。

开发者只需要关心在一个并发单元的输入与输出的影响,而不需要再考虑类似于修改共享内存/数据对其它程序的影响。

优质文章,推荐阅读:

Python 中如何实现参数化测试?

好的编程语言具备哪些特性?

Python 3 既是激进的又是克制的,这些提议被否决了

Python 之父的解析器系列之五:左递归 PEG 语法

感谢创作者的好文

python 协程_Python 协程与 Go 协程的区别(一)相关推荐

  1. python多线程多进程多协程_python 多进程、多线程、协程

    1.python的多线程 多线程就是在同一时刻执行多个不同的程序,然而python中的多线程并不能真正的实现并行,这是由于cpython解释器中的GIL(全局解释器锁)捣的鬼,这把锁保证了同一时刻只有 ...

  2. python getopt模块_python里argparse模块和getopt模块的区别

    展开全部 argparse是用于脚本带参数使用的,假设你有如下脚本名为prog.py,内容如下:e69da5e6ba9062616964757a686964616f31333363363464impo ...

  3. python defaultdict(list)_Python collections.defaultdict() 与 dict的使用和区别

    在Python里面有一个模块collections,解释是数据类型容器模块.这里面有一个collections.defaultdict()经常被用到.主要说说这个东西. 综述: 这里的defaultd ...

  4. python跳出循环关键字_Python跳出for循环continue与break的区别

    在for和while循环语句中,当循环条件满足时,就会一直循环,如果想中途退出循环,该怎么办?如果想停止本次循环,而不终止整个循环,该怎么办?如果我想写个不执行任何操作的语句,该怎么写? Python ...

  5. python大括号用法_Python中的大括号和方括号有什么区别?

    花括号创建 dictionaries或 sets.方括号创建 lists. 它们被称为字面量;设置文字: aset = {'foo', 'bar'} 或字典字面量: adict = {'foo': 4 ...

  6. python 协程可以嵌套协程吗_Python线程、协程探究(2)——揭开协程的神秘面纱...

    一.上集回顾 在上一篇中我们主要研究了python的多线程困境,发现多核情况下由于GIL的存在,python的多线程程序无法发挥多线程该有的并行威力.在文章的结尾,我们提出如下需求: 既然python ...

  7. python 协程_Python多任务协程

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源).为啥说它是一个执行单元,因为它自带CPU ...

  8. python从网址爬图片协程_python 用 gevent 协程抓取海量网页

    python作为爬虫利器,抓网页的方式简洁明了.爬成百上千的网页,都可以很快爬完,但是如果网页数量上万呢?速度就不能忍受了. 这是一段爬取页面的函数,用了requests库:1 2 3 4 5impo ...

  9. python 协程 php,python3.x,协程_python协程练习部分代码的理解?,python3.x,协程,asyncio - phpStudy...

    python协程练习部分代码的理解? import asyncio import threading async def wget(host): print('wget {}'.format(host ...

最新文章

  1. 彩图完美解释:麦克斯韦方程组
  2. 趋势 | 人工智能领域十大最具成长性技术展望
  3. 破解 Windows 2003终端服务许可证
  4. spring aop搭建(2) :基于代码的实现
  5. java栈和队列验证回文串_栈和队列的基本操作及其应用(回文判断)
  6. Pytorch 神经网络训练过程
  7. 恒大和小米双双否认外界谣言,此前有人宣称小米将接手恒大造车
  8. 证件照尺寸怎么修改?这三个好用的方法你知道吗?
  9. 淘宝下单高并发解决方案
  10. 获取上周一上周日,和大上周一和大上周日的时间
  11. HomeKit 设备接入协议
  12. Android辅助功能之自动安装apk
  13. 什么是前端编程中的骨,肉,魂
  14. ArkID 一账通:企业级开源IDaaS/IAM平台系统
  15. CSS3的动画与变形
  16. 频上“热搜”的人工智能专业,主要学什么?为什么如此火爆?
  17. 计科学硕考研初试经验贴(11408)
  18. 井柏然自己的字体,手写语录合集
  19. PDF转成高清图片怎么转?借助这几款软件轻松搞定
  20. 《现代量子力学》Sakurai 习题答案链接

热门文章

  1. openstack-neutron基本的网络类型
  2. 解救人质的android游戏,黑帽子解救人质全关卡解锁版 1.03 安卓版
  3. python课件_讲座直播 | Python在线课堂第二周
  4. Ant Design Pro 改变默认启动端口号
  5. linux 占用缓存前10_Linux 中的零拷贝技术
  6. mysql binlog 目录_怎么查看mysql 的binlog日志存放的位置(linux和win)
  7. Lua和C语言的交互——C API
  8. Linux下的USB总线驱动 1
  9. mysql给数据做排名_mysql给数据统计做排名
  10. Java自带的广告怎么删掉_如何屏蔽电脑上的弹窗广告?