协程

go中的sync.Mutex

南笙酒味 提交于 2019-12-05 00:02:15
golang中的互斥锁定义在 src/sync/mutex.go 源码中给出了互斥量公平的解释,差不多意思如下: 互斥锁可以处于两种操作模式:normal和starvation。 在normal模式下,新加入竞争锁队列的协程也会直接参与到锁的竞争中来,处于starvation模式下,所以新加入的协程将直接进入等待队列中挂起,直到其等待队列之前的协程全部执行完毕。 normal模式下, 协程的竞争等待时间如果大于1ms,就会进入starvation模式。 starvation模式下,该协程 是等待队列中的最后一个工作协程,或者它挂起等待时长不到1ms,则切换回normal模式。 state用于存储Mutex的状态量,具体可以看下下面const,state的最低位(mutexLocked)用于表示是否上锁,低二位(mutexWoken)用来表示当前锁是否唤醒,低三位(mutexStarving)用来表示当前锁是否处于starvation模式。剩下位数据state>> mutexWaitershif ( mutexWaitershif为3 )用来表示当前被阻塞的协程数量,sema是一个信号量,协程阻塞的依据。 type Mutex struct { state int32 sema uint32 } const ( mutexLocked = 1 << iota // mutex is

go随聊-sync.WaitGroup

拈花ヽ惹草 提交于 2019-12-04 23:41:56
GO提供了sync包和channel来解决协程同步和通讯。新手对channel通道操作起来更容易产生死锁,如果时缓冲的channel还要考虑channel放入和取出数据的速率问题。sync.WaitGroup是等待一组协程结束,它实现了一个类似任务队列的结构,你可以向队列中加入任务,任务完成后就把任务从队列中移除,如果队列中的任务没有全部完成,队列就会触发阻塞以阻止程序继续运行。本文主要介绍sync.WaitGroup。 package sync type WaitGroup struct 三个重要函数: //调用Add来设置等待的协程(goroutine)数量 func (wg *WaitGroup) Add(delta int) //协程(goroutine)完成后调用Done,内部其实就是将值-1 func (wg *WaitGroup) Done() //Wait用来阻塞即等待wg值为0,直到所有协程(goroutine)完成才会向下执行 func (wg *WaitGroup) Wait() 使用例子 定义任务及 WaitGroup var wg sync.WaitGroup //任务每个1秒打印一次,打印5次 func process(name string) { for i:=0;i<5;i++ { fmt.Println("process[",name,"]

Golang的sync.WaitGroup陷阱

故事扮演 提交于 2019-12-04 23:41:38
sync.WaitGroup 是并发环境中,一个相当常用的数据结构,用来等待所有协程的结束,在写代码的时候都是按着例子的样子写的,也没用深究过它的使用。前几日想着能不能在协程中执行 Add() 函数,答案是不能,这里介绍下。 陷阱在WaitGroup的3个函数的调用顺序上。先回顾下3个函数的功能: Add(delta int) :给计数器增加delta,比如启动1个协程就增加1。 Done() :协程退出前执行,把计数器减1。 Wait() :阻塞等待计数器为0。 考一考 下面的程序是创建了协程father,然后father协程创建了10个子协程,main函数等待所有协程结束后退出,看看下面代码有没有什么问题? package main import ( "fmt" "sync" ) func father ( wg * sync . WaitGroup ) { wg . Add ( 1 ) defer wg . Done ( ) fmt . Printf ( "father\n" ) for i := 0 ; i < 10 ; i ++ { go child ( wg , i ) } } func child ( wg * sync . WaitGroup , id int ) { wg . Add ( 1 ) defer wg . Done ( ) fmt . Printf (

Golang 中使用WaitGroup的那点坑

吃可爱长大的小学妹 提交于 2019-12-04 23:36:08
sync.WaitGroup对于Golang开发者来说并不陌生,其经常作为多协程之间同步的一种机制。用好它势必会让你事半功倍,但是一旦错用将引发问题。关于WaitGroup的使用网上有很多例子,在此就不做介绍了,我想说的是我在项目中使用WaitGroup遇到的坑。 在项目中,因为服务器有同步需求, 所以直接使用了WaitGroup,但是未考虑使用场景,结果在项目上线之后,高峰期的时候客户端经常出现卡顿,经过多方查找,才发现如果使用WaitGroup的时候,未启动单独的goroutine,那么极有可能造成主线程的阻塞,所以我做了下面的测试(测试中,我把WaitGroup置于协程内): func main() { fmt.Println("main-1") testchan() fmt.Println("main-2") } func testchan() { fmt.Println("testchan-1") go func() { var wg *sync.WaitGroup = new(sync.WaitGroup) fmt.Println("testchan-2") testchan1(wg) fmt.Println("testchan-5") wg.Wait() time.Sleep(time.Duration(5) * time.Second) fmt.Println(

【python】进程、线程、协程对比

偶尔善良 提交于 2019-12-04 20:44:09
请仔细理解如下的通俗描述 有一个老板想要开个工厂进行生产某件商品(例如剪子) 他需要画一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的为了能够生产剪子而准备的资源称之为:进程 只有生产线是不能够进行生产的,所以老板得找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程 这个老板为了提高生产率,想到了3种办法 在这条生产线上多招些工人,一起来做剪子,这样效率是成倍增长,即单进程多线程方式 老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及草料毕竟有限,所以老板又花了些财力物理购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程,多线程方式 老板发现,现在已经又和很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时没事或者再等待某些条件(比如等待另一个生产完谋道工序之后他才能再次工作),那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待默写条件,可以充分利用这个时间去做其它事情,其实这就是协程方式 简单总结 进程是资源分配的单位 进程是操作系统调度的单位 进程切换需要的资源量最大,效率很低 线程切换需要的资源一般,效率一般(当然了,再不考虑GIL的情况下)

Python 协程

岁酱吖の 提交于 2019-12-04 19:03:27
目录 协程基础 底层实现 介绍 安装 应用 协程实现 协程爬虫 协程实现socket并发 协程基础 底层实现 协程的底层是使用greenlet模块来实现的 from greenlet import greenlet def func1(): print("eat start")# 2 g2.switch() print("eat end")# 4 g2.switch() def func2(): print("play start")# 3 g1.switch() print("play end")# 5 g1 = greenlet(func1) g2 = greenlet(func2) g1.switch()# 1 介绍 当遇到IO操作时将程序切换到其他函数继续执行会提高CPU的利用效率 一个线程可以开启500个协程 更适用于网络操作中 安装 pip install gevent 应用 协程实现 from gevent import monkey;monkey.patch_all() # 将下面导入的所有的包中的阻塞操作封装成gevent可以识别的阻塞 # 没有这行代码time.sleep语句是不被gevent识别的 # 使用gevent一定要将这一行代码放到开头 import time import gevent def func1(): print("eat start")

python基础(35):协程

非 Y 不嫁゛ 提交于 2019-12-04 17:35:02
1. 前言 之前我们学习了线程、进程的概念,了解了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位。按道理来说我们已经算是把cpu的利用率提高很多了。但是我们知道无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理他们之间的切换。 随着我们对于效率的追求不断提高,基于单线程来实现并发又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。 为此我们需要先回顾下并发的本质:切换+保存状态。 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长。 在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 : 一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。 为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级

面试 协程

社会主义新天地 提交于 2019-12-04 16:18:29
协程(corouutine):轻量级的线程,不存在上下文切换,能在多个任务之间调度的多任务方式,可以使用,yield实现 线程和进程的操作是由程序触发系统接口,最后的执行者是系统,它本质上是操作系统提供的功能。而协程的操作则是程序员指定的,在python中通过yield,人为的实现并发处理。 协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时。协程,则只使用一个线程,分解一个线程成为多个“微线程”,在一个线程中规定某个代码块的执行顺序。 协程的适用场景:当程序中存在大量不需要CPU的操作时(IO)。 简单多任务协程实列: import time import threading def task_1(): print(threading.current_thread()) while True: print('---1---') time.sleep(1) yield def task_2(): print(threading.current_thread()) while True: print('---2---') time.sleep(1) yield def main(): t1=task_1() t2=task_2() while True: next(t1) next(t2) if __name__ == '__main__':

面试-进程 线程 协程

旧巷老猫 提交于 2019-12-04 16:12:19
一、进程 进程的概念 1.进程是一个实体。每个进程都有自己的地址空间(CPU分配)。实体空间包括三部分: * 文本区域:存储处理器执行的代码。 * 数据区域:存储变量或进程执行期间使用的动态分配的内存。 * 堆栈:进程执行时调用的指令和本地变量。 2.进程是一个“执行中的程序”。 程序是指令与数据的有序集合,程序本身是没有生命的,只有CPU赋予程序生命时(CPU执行程序),它才能成为一个活动的实体,称为“进程”。 概括来说,进程就是一个具有独立功能的程序在某个数据集上的一次运行活动 进程的特点 * 动态性:进程是程序的一次执行过程,动态产生,动态消亡。 * 独立性:进程是一个能独立运行的基本单元。是系统分配资源与调度的基本单元。 * 并发性:任何进程都可以与其他进程并发执行。 二、并发与并行 并发:在操作系统中,某一时间段,几个程序在同一个CPU上运行,但在任意一个时间点上,只有一个程序在CPU上运行。 当有多个线程时,如果系统只有一个CPU,那么CPU不可能真正同时进行多个线程,CPU的运行时间会被划分成若干个时间段,每个时间段分配给各个线程去执行,一个时间段里某个线程运行时,其他线程处于挂起状态,这就是并发。并发解决了程序排队等待的问题,如果一个程序发生阻塞,其他程序仍然可以正常执行。 并行:当操作系统有多个CPU时,一个CPU处理A线程,另一个CPU处理B线程

kotlin协程

大城市里の小女人 提交于 2019-12-04 15:06:15
一个进程可以有多个线程,一个线程可以有多个协程,但某一时刻 只能有一个协程在运行,多个协程分享该线程分配到的计算机资源 优点: 操作系统切换线程,会产生一定的消耗,而协程 则是工作于线程之上, 协程可以由程序自己来控制,无需操作系统来进行调度(这样大大降低了开销) 场景:开启10万个协程执行hello,不会有问题, 但开启10万个线程去执行hello,可能就会出现 ”out of memory“ 协程中的delay:用于挂起协程,不会阻塞线程 来源: https://www.cnblogs.com/acg88688/p/11870573.html