进程、线程和协程

进程的定义:

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

线程的定义:

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

进程和线程的关系:

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

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 := <-jobs // 利用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 <- j
fmt.Println("sent job", j)
}
close(jobs) // 写完最后的数据,紧接着就close掉
fmt.Println("close(jobs)")
}() fmt.Println("sent all jobs")
<-done // 让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 协程与go协程的区别的更多相关文章

  1. Python—进程、线程、协程

    一.线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 方法: ...

  2. Python PEP 492 中文翻译——协程与async/await语法

    原文标题:PEP 0492 -- Coroutines with async and await syntax 原文链接:https://www.python.org/dev/peps/pep-049 ...

  3. python进程、线程、协程(转载)

    python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资 ...

  4. Python进程、线程、协程详解

    进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...

  5. python——进程、线程、协程

    Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env pytho ...

  6. python单线程,多线程和协程速度对比

    在某些应用场景下,想要提高python的并发能力,可以使用多线程,或者协程.比如网络爬虫,数据库操作等一些IO密集型的操作.下面对比python单线程,多线程和协程在网络爬虫场景下的速度. 一,单线程 ...

  7. Python 线程和进程和协程总结

    Python 线程和进程和协程总结 线程和进程和协程 进程 进程是程序执行时的一个实例,是担当分配系统资源(CPU时间.内存等)的基本单位: 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其 ...

  8. Python Web学习笔记之Python多线程和多进程、协程入门

    进程和线程究竟是什么?如何使用进程和线程?什么场景下需要使用进程和线程?协程又是什么?协程和线程的关系和区别有哪些? 程序切换-CPU时间的分配 首先,我们的任何一个程序都需要运行在一个操作系统中,如 ...

  9. 消息/事件, 同步/异步/协程, 并发/并行 协程与状态机 ——从python asyncio引发的集中学习

    我比较笨,只看用await asyncio.sleep(x)实现的例子,看再多,也还是不会. 已经在unity3d里用过coroutine了,也知道是“你执行一下,主动让出权限:我执行一下,主动让出权 ...

  10. Python并发编程系列之协程

    1 引言 协程是近几年并发编程的一个热门话题,与Python多进程.多线程相比,协程在很多方面优势明显.本文从协程的定义和意义出发,结合asyncio模块详细讲述协程的使用. 2 协程的意义 2.1 ...

随机推荐

  1. Netty启动流程剖析

    编者注:Netty是Java领域有名的开源网络库,特点是高性能和高扩展性,因此很多流行的框架都是基于它来构建的,比如我们熟知的Dubbo.Rocketmq.Hadoop等,针对高性能RPC,一般都是基 ...

  2. GO 基础学习笔记(4)| 参数传递

    Go 语言的命令行参数传递 //通过下面实操可知,通过命令行传递文件和参数 可复制 1 package main 2 3 import( 4 "fmt" 5 "os&qu ...

  3. Javascript模块化开发2——Gruntfile.js详解

    一.grunt模块简介 grunt插件,是一种npm环境下的自动化工具.对于需要反复重复的任务,例如压缩.编译.单元测试.linting等,自动化工具可以减轻你的劳动,简化你的工作.grunt模块根据 ...

  4. css字体图标的制作

    我介绍的这个办法是直接在 "阿里巴巴图标库"中制作的,方便快捷 1. 首先到 "阿里巴巴图标库"中找到你想要的图片,然后选择加入购物车 接着我们点击右上角的购物 ...

  5. nyoj 50-爱摘苹果的小明 (比较)

    50-爱摘苹果的小明 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:10 submit:15 题目描述: 小明家的院子里有一棵苹果树,每到秋天树上就 ...

  6. 领扣(LeetCode)有效的括号 个人题解

    给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空字符串可被认 ...

  7. leetcode-242 判断两个字符串是不是 Anagram ?

    题目描述 假设给定两个字符串 s 和 t, 让我们写出一个方法来判断这两个字符串是否是字母异位词? 字母异位词就是,两个字符串中含有字母的个数和数量都一样,比如: Example 1: Input: ...

  8. RevitAPI 隐藏UI读取Revit文件

    1.1. 新建一个控制台项目 1.2. 添加Revit API引用 我们找到revit安装目录下的这两个DLL添加到项目引用中 RevitNET.dll RevitAPI.dll 修改属性:复制本地: ...

  9. 微信小程序使用 ECharts 实现数据可视化

    微信小程序使用 ECharts 显示图表 首先创建微信小程序 这里就不再赘述 下载 GitHub 上的 ecomfe/echarts-for-weixin 下载后解压,打开文件夹,里面的 ec-can ...

  10. C#变量---xdd

    cshape(c#)学习笔记 1. string str1=Console.ReadLine();//键盘输入的默认为字符串 2.  Console.WriteLine('你的成绩是'+a+'分'); ...