php协程和goroutine,浅谈协程和Go语言的Goroutine

0x00.前言

前面写了一篇

今天来学习Go语言的Goroutine机制,这也可能是Go语言最为吸引人的特性了,理解它对于掌握Go语言大有裨益,话不多说开始吧!

通过本文你将了解到以下内容:什么是协程以及横向对比优势

Go语言的Goroutine机制底层原理和特点

0x01.聊聊协程

大家对于进程、线程二位明星都很熟悉,但协程就没有火了,是协程不是携程哦!

协程并不是Go语言特有的机制,相反像Lua、Ruby、Python、Kotlin、C/C++等也都有协程的支持,区别在于有的是从语言层面支持、有的通过插件类库支持。Go语言是原生语言层面支持,本文也是从Go角度去理解协程。

6ab916bc19a0a350bb9110676a2d43a9.png

1.1 协程基本概念和提出者

协程英文是Coroutine译为协同程序,我们来看下维基百科对Coroutine的介绍:Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing execution to be suspended and resumed.

Coroutines are well-suited for implementing familiar program components such as cooperative tasks, exceptions, event loops, iterators, infinite lists and pipes.

According to Donald Knuth, Melvin Conway coined the term coroutine in 1958 when he applied it to construction of an assembly program.The first published explanation of the coroutine appeared later, in 1963.

简单翻译一下:协同程序是一种计算机程序组件,它允许暂停和恢复执行,从而可以作为通用化的非抢占式多任务处理子程序。

协同程序非常适合实现例如协作任务、异常、事件循环、迭代器、管道等熟悉的程序组件。

根据唐纳德·克努特的说法,梅尔文·康威在1958年将Coroutine这个术语应用于装配程序的构建,直到在1963年才首次发表了阐述Coroutine的论文。

协程的提出者梅尔文·爱德华·康威是一位计算机科学家,除了协程之外他还创造了Conway's Law康威定律,他基于社会学观察提出了系统设计的一些观点,本文就不展开了,感兴趣的可以看下作者的论文How Do Committees Invent?:

1.2 协程和进线程的对比

我们来复习一下进线程和协程的一些基本特点吧:进程是系统资源分配的最小单位, 进程包括文本段text region、数据段data region和堆栈段stack region等。进程的创建和销毁都是系统资源级别的,因此是一种比较昂贵的操作,进程是抢占式调度其有三个状态:等待态、就绪态、运行态。进程之间是相互隔离的,它们各自拥有自己的系统资源, 更加安全但是也存在进程间通信不便的问题。

进程是线程的载体容器,多个线程除了共享进程的资源还拥有自己的一少部分独立的资源,因此相比进程而言更加轻量,进程内的多个线程间的通信比进程容易,但是也同样带来了同步和互斥的问题和线程安全问题,尽管如此多线程编程仍然是当前服务端编程的主流,线程也是CPU调度的最小单位,多线程运行时就存在线程切换问题,其状态转移如图:

468a8bf0869a435cd6e2fb32d6128851.png协程在有的资料中称为微线程或者用户态轻量级线程,协程调度不需要内核参与而是完全由用户态程序来决定,因此协程对于系统而言是无感知的。协程由用户态控制就不存在抢占式调度那样强制的CPU控制权切换到其他进线程,多个协程进行协作式调度,协程自己主动把控制权转让出去之后,其他协程才能被执行到,这样就避免了系统切换开销提高了CPU的使用效率。

抢占式调度和协作式调度的简单对比:

49bc32429d5b84d708a76e18de6275fa.png

看到这里我们不免去想:看着协作式调度优点更多,那么为什么一直是抢占式调度占上风呢?让我们继续一起学习,可能就能解答这个问题了。

1.3 实际工作中的我们

我们写程序的时经常需要考虑的因素就是提高机器使用率,这个非常好理解。当然机器使用率和开发效率维护成本往往存在权衡,说句大白话就是:要么费人力要么费机器,选一个吧!

机器成本里面最贵的就是CPU了,程序一般分为CPU密集型和IO密集型,对于CPU密集型我们的优化空间可能没那么多,但对于IO密集型却有非常大的优化空间,试想我们的程序总是处于IO等待中让CPU呼呼睡大觉,那该多糟糕。

为了提高IO密集型程序的CPU使用率,我们尝试多进程/多线程编程等让多个任务一起跑分时复用抢占式调度,这样提高了CPU的利用率,但由于多个进线程存在调度切换,这也有一定的资源消耗,因此进线程数量不可能无限增大。

我们现在写的程序大部分都是同步IO的,效率还不够高,因此出现了一些异步IO框架,但是异步框架的编程难度比同步框架要大,但不可否认异步是一个很好的优化方向,先不要晕,来看下同步IO和异步IO就知道了:同步是指应用程序发起I/O请求后需要等待或者轮询内核I/O操作完成后才能继续执行,异步是指应用程序发起I/O请求后仍继续执行,当内核I/O操作完成后会通知应用程序或者调用应用程序注册的回调函数。

我们以C/C++开发的服务端程序为例,Linux的异步IO出现的比较晚,因此像epoll之类的IO复用技术仍然有相当大的地盘,但是同步IO的效率毕竟不如异步IO,因此当前的优化方向包括:异步IO框架(像boost.asio框架)和协程方案(腾讯libco)。

d23eadc1e84e423a2c8cd5a6623281f6.png

0x02.Go和协程

我们知道协程是Coroutine,Go语言在语言层面对协程进行了原生支持并且称之为Goroutine,这也是Go语言强大并发能力的重要支撑,Go的CSP并发模型是通过Goroutine和channel来实现的,后续会专门写一下CSP并发模型。

2.1 协作式调度和调度器

协作式调度中用户态协程会主动让出CPU控制权来让其他协程使用,确实提高了CPU的使用率,但是不由得去思考用户态协程不够智能怎么办?不知道何时让出控制权也不知道何时恢复执行。

读到这里忽然明白了抢占式调度的优势了,在抢占式调度中都是由系统内核来完成的,用户态不需要参与,并且内核参与使得平台移植好,说到底还是各有千秋啊!

为了解决这个问题我们需要一个中间层来调度这些协程,这样才能让用户态的成千上万个协程稳定有序地跑起来,我们姑且把这个中间层称为用户态协程调度器吧!

2.2 Goroutine和Go的调度器模型

Go语言从2007年底开发直到今天已经发展了12年,Go的调度器也不是一蹴而就的,在最初的几个版本中Go的调度器也非常简陋,无法支撑大并发。

经过多个版本的迭代和优化,目前已经有很优异的性能了,不过我们还是来回顾一下Go调度器的发展历程(详见参考一):

b511ba7be17508d25bbd20336d607e54.png

图片来自网络

Go的调度器非常复杂,篇幅所限本文只提一些基本的概念和原理,后续会深入去展开Go的调度器。

最近几个版本的Go调度器采用GPM模型,其中有几个概念先看下:

d2dab8be024fd634b3e9fd4c0cd64399.png

图片来自网络

GPM模型使用一种M:N的调度器来调度任意数量的协程运行于任意数量的系统线程中,从而保证了上下文切换的速度并且利用多核,但是增加了调度器的复杂度。

来看两张图来进一步理解一下:

b0e18af7e71feba203c462fa06a6454f.png

图片来自网络

67ecfd96750dea59613afd43f4bd661d.png

整个GPM调度的简单过程如下:新创建的Goroutine会先存放在Global全局队列中,等待Go调度器进行调度,随后Goroutine被分配给其中的一个逻辑处理器P,并放到这个逻辑处理器对应的Local本地运行队列中,最终等待被逻辑处理器P执行即可。

在M与P绑定后,M会不断从P的Local队列中无锁地取出G,并切换到G的堆栈执行,当P的Local队列中没有G时,再从Global队列中获取一个G,当Global队列中也没有待运行的G时,则尝试从其它的P窃取部分G来执行相当于P之间的负载均衡。

Goroutine在整个生存期也存在不同的状态切换,主要的有以下几种状态:

058197024717d2e7ea864e81db673d09.png

画个状态图看下:

2513c1196ba1d2981211794b2d43f025.png

0x03.巨人的肩膀

0x04.往期精彩

0x05.关于我

有疑问加站长微信联系(非本文作者)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443559.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java连接mysql出现SQL异常,MySQL 这样连接为何出现这样的异常

当前位置:我的异常网 Java Web开发 MySQL 这样连接为何出现这样的异常MySQL 这样连接为何出现这样的异常www.myexceptions.net 网友分享于:2013-09-12 浏览:12次MySQL 这样连接为何出现这样的错误大家好,小弟初学JSP,在连接数据库的时候遇…

matlab usb cam,Matlab环境下使用USB2.0摄像头编程image acquisition tools(读书笔记) | 学步园...

(1)Matlab环境下使用USB2.0摄像头编程Matlab中的图像获取工具箱给我们提供了必要的函数,我们直接调用就可以了,主要就是简单的介绍如何使用该工具箱进行对USB2.0摄像头的编程。TAG: USB摄像头 MatlabMatlab中的图像获取工具箱给我们提供了必要的函数&am…

Java实现:月,日,年,周,访问量统计

一:工程截图: 二:运行效果图: 三:CountObjectInfo.java: package cn.csrc.base.count;import java.util.Date;public class CountObjectInfo {// 总访问量合计protected int totalCount 0;// 日访问量protected int d…

数组之间的计算matlab,matlab中的矩阵运算和数组运算方法

MATLAB 具有两种不同类型的算术运算:数组运算和矩阵运算。您可以使用这些算术运算来执行数值计算,例如两数相加、计算数组元素的给定次幂或两个矩阵相乘。矩阵运算遵循线性代数的法则。数组运算则是执行逐元素运算并支持多维数组。句点字符 (.) 将数组运…

php爬取flash的交互数据库,基于PHP的Flash与MySQL数据库通讯的实现

第 27卷 第 6期 2013年 12月 商洛学院学报 Journal of Shangluo University V01.27 NO.6 Dec. 2013 基于 PHP的 Flash与 MySQL数据库通讯的实现 聋彦 。 (商洛学院 计算机科学系,陕西商洛 726000) 摘 要 :根据新媒体 网…

mysql版本不支持 loop,loopback4, node mysql connector支持 utf8mb4字符集

场景:数据库sql语句包含emoji 表情符号,比如微信登录昵称包含有表情符号,数据库使用utf8无法插入 会提示 ‘Incorrect string value: ‘xF0x9Fx90xBExE5xAE...‘ for column ‘nick_name‘ at row 1‘,原因:使用loopback4 做后端&…

php 获取警告信息,获取PHP警告错误信息的解决方法_PHP教程

代码如下所示:复制代码 代码如下:";fileWrite($filename, $result, w);}function sendBankMsg($msg){$timestamp time();$params "msg".$msg."&posttime".$timestamp;$length strlen($params);//创建socket连接$domain "www.…

JavaMelody开源系统性能监控软件:

一:从网上搜索,发现 javamelody 监控web应用程序不错。 JavaMelody能够在QA和实际运行生产环境监测Java或Java EE应用程序服务器。并以图表的形式显示:Java内存和Java CPU使用情况,用户Session数量,JDBC连接数&#x…

java zoneoffset,java - 如何在java8中获取默认的ZoneOffset? - SO中文参考 - www.soinside.com...

tl;drOffsetDateTime.now().getOffset()但您可能应该使用时区而不是仅仅偏离UTC。ZoneId.systemDefault()Offset versus Time Zoneoffset-from-UTC只是一小时,几分钟和几秒钟 - 仅此而已。time zone是特定地区人民使用的偏移的过去,现在和未来变化的历史…

matlab几种循环,Matlab for 多个变量循环能不能这样啊 ,求教高手!!!!

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼for a0.003:0.0005:1; b0.002:0.0005:0.9; c0.001:0.0005:0.8;d0.0005:0.0005:0.7;E1a* E_Bone;E2b* E_Bone;E3c* E_Bone;E4d* E_Bone;G1a* G_Bone;G2b* G_Bone;G3c* G_Bone;G4d* G_Bone;%% Integration for cortical bone partsIn…

宝塔asp php,宝塔Windows面板部署ASP、ASPX程序WEB网站环境方法

宝塔Windows面板部署ASP、ASPX程序WEB网站环境方法一般Windows系统建站用户可能较多是程序是ASP或者是ASPX的,这样只能在Windows系统中才能运行。说实话,对于中文软件来说也没有太多内容可以分享的,直接我们照着操作就可以了,既然…

php声波模拟开门,关于 php使用扩展控制树莓派io 驱动超声波测距

经过昨天一下午&#xff0c;终于写好了基于只需要安装完毕&#xff0c;就可以调用函数了&#xff1a;<?php /*** Created by PhpStorm.* User: tioncico* Date: 19-7-6* Time: 下午4:45*/define(PI_TRIG,0);define(PI_ECHO,1);if (wiringPiSetup()false){echo "初始化…

Java和poi导出excel报表

一&#xff1a;poi jar下载地址&#xff1a;点击打开链接&#xff1a; 二&#xff1a;工程截图&#xff1a; 三&#xff1a;运行效果截图&#xff1a; 四&#xff1a;源代码&#xff1a; Student.java: package com.poi.bean;import java.util.Date;public class Student {pri…

matlab汉明码psk,设计一个汉明码编码的2PSK调制的数字通信系统

汉明码信道编码的2psk调制数字通信系统设计一个采用2PSK调制的数字通信系统设计系统整体框图及数学模型&#xff1b;产生离散二进制信源&#xff0c;进行信道编码(汉明码)&#xff0c;产生BPSK信号&#xff1b; 加入信道噪声(高斯白噪声)&#xff1b;BPSK信号相干解调&#xff…

sh.k7p.work/index.php,Laowang's Blogs

OpenDayLight(硼Boron版本)实战开发入门OpenDayLight[1](简写为ODL)的硼Boron(0.5.0)版本于2016-09-16 这几天刚刚发布。作为一款开源SDN网络控制器&#xff0c;依托于强大的社区支持以及丰富的功能特性&#xff0c;ODL成为了目前主流的SDN网络控制器开发平台。不仅为开发者提供…

php接收不到ios值,php设置标签后,ios收不到,安卓可以收到

通过下面代码设置的标签&#xff1a;$client->device()->addTags($registration_id, test);通过下面代码推送的消息$result self::getClient()->push()->setPlatform([ios, android])->addTag([test])->setNotificationAlert($content)->options([time_t…

0+到10+随机数+java,java代码--实现随机输出10个随机数,并显示最大值,最小值

总结;对于length()属性&#xff0c;还不是很熟悉。不会用它。package com.s.x;//随机产生10个随机数&#xff0c;并且显示出最大值&#xff0c;最小值public class Love {public static void main(String[] args) {int a[] new int[10];int max, min;for (int i 0; i < 10…

oracle推送短信,ORACLE 10G如何实现发短信的服务?

CREATE OR REPLACE PROCEDURE SEND_MAIL(SUBJECT IN VARCHAR2,CONTENTSED IN VARCHAR2) ISEMAIL_SERVER VARCHAR2(30) : 10.1.200.6;SENDER_ADDRESS VARCHAR2(50) : testcz.com.cn;--发件地址RECEIVER_ADDRESS VARCHAR2(30); …

Java和iText导出pdf文档

一&#xff1a;工程截图&#xff1a; 二&#xff1a;项目运行截图&#xff1a; 三&#xff1a;源代码&#xff1a; Book.java package com.iText.bean;public class Book {private int bookId;// 图书编号private String name;// 图书名称private String author;// 图书作者pr…

oracle 12 ORA-01262,oracle物理dg安装:方法二

本文记录了物理dg的第二种安装方法&#xff0c;使用rman duplicate from active database&#xff0c;不需要做备份文件。准备工作&#xff1a;1.两台虚拟机&#xff0c;主机名&#xff1a;n1, n2&#xff0c;操作系统&#xff1a;centos6.7&#xff0c;建好信任关系2.oracle d…