• 协程和 C++ Boost库的Coroutine2


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    摘要

    协程是一种轻量级的并发单位,相比于线程,它具有更小的内存占用和更高效的调度,适用于I/O密集型和计算密集型场景。Boost.Coroutine2是一种协程实现,它是一种特殊控制流,允许在某些位置暂停和恢复执行的子例程。它保留了本地执行状态,并允许重入子例程多次。然而,Boost.Coroutine2的多个实例是顺序执行的,不支持并行执行。在并发性能和资源利用率方面,Goroutine相比于Coroutine2具有更优秀的表现。因此,在编写并发程序时,建议根据实际需求选择适合的并发模型和相应的语言机制。Boost.Coroutine2适用于多个任务的协助和生成器模式等场景。


    为什么不是boost.coroutine?

    boost官方团队已经声明现已弃用,推荐使用coroutine2。

    线程与协程

    线程

    线程是操作系统提供的一种并发执行的机制,它具有以下特点:

    运行在系统态,由操作系统调度。
    线程实例之间各自独立运行,共享堆内存,栈空间是各自独占的。
    一个初始线程会占用几兆内存,即便它没做什么。
    线程之间的切换需要一定的开销。
    有完善的同步锁、数据共享机制。

    协程

    协程是轻量级的并发模型,它具有以下特点:

    运行在用户态,由程序员自己调度。
    协程实例之间共享堆内存和栈空间。
    一个初始协程只占用几KB内存。
    协程之间的切换开销极小。
    需要开发人员自己实现同步机制。

    为什么不介绍C++20标准的协程

    C++20引入了无栈协程的特性,为更好的开发异步编程做好了准备。但是由于该版本的协程实现方法一直有很大的争议,协程通过决议的时间很晚,所以实际仅提供了三个关键字来支持协程实现,真正想用协程还要自己实现协程库。然后来不及在C++20中提供协程相关的支持库,像std::generator、std::task等等,需要在C++23中才能提供,有了这些库的支持,基本可以使用标准库的协程了,C++23太新了,编译器的支持当前还没跟上,另外它的实现和使用跟coroutine2差异很小,所以我可能会继续选择使用coroutine2。

    C++协程与golang的goroutine

    coroutine2跟goroutine不一样,它实际上无法并行

    Goroutine是Go语言中轻量级的并发单位,它由Go运行时系统管理和调度,能够在多核处理器上并行执行。而Coroutine2则是一种协程,它是由用户代码自行调度和管理的轻量级线程,通常只在一个线程中顺序执行或者交替,不支持并行执行。

    Goroutine相比于Coroutine2具有更小的内存占用和更高效的调度,因此在并发性能和资源利用率方面更加优秀。Go语言通过Goroutine和Channel等机制,提供了一种简洁而高效的并发编程范式,使得开发人员能够轻松地编写并发的程序。

    需要注意的是,虽然Coroutine2本身不支持并行执行,但通过一些技术手段可以将Coroutine2组合成并发的执行流,例如使用线程池或者协程池等方式来并发执行Coroutine2。但是这种方式的并发性能和资源利用率相比Goroutine可能会有所下降。

    这样比较下看coroutine2对协程的实现好像很鸡肋,但其实goroutine与coroutine行为上的不用也表明了它们的应用场景也不同:
    Boost.Coroutine2 可以被视为boost提供的一种特殊控制流,允许在某些位置暂停和恢复执行的子例程。 它保留了本地执行状态,并允许重入子例程多次(如果必须在函数调用之间保持状态,则很有用)。如(生成器、协作式多任务处理)都是它适合的场景,代码结构很简介,这部分优于goroutine。

    在这里插入图片描述

    二、使用步骤

    1.引入库

    依赖库:Boost.Context
    需要语言版:C++11版本
    头文件位置:#include

    2.核心类

    coroutine2中只有两个核心的类:pull_type,push_type。

    在 Boost.Coroutine2 中,协程只能单向传递数据,数据只能单向的从一个代码块流向另一个代码块。流入流出分别对应着 push_type 和 pull_type 类型,由这两个类型组成协程间跳转的通道,同时也是数据传递的通道。

    pull_type

    pull_type 用于从协程中获取数据,它提供了以下方法:
    begin():返回一个迭代器,可以迭代获取协程中的数据。
    get():获取协程中的下一个数据。
    operator():调用协程的下一个操作,并返回协程是否结束。

    push_type

    push_type 用于向协程中传递数据,它提供了以下方法:
    operator():向协程中传递数据,并返回协程是否结束。

    单个协程

    	/*
    	 * 斐波那契数列
    	 */
    	boost::coroutines2::coroutine<int>::pull_type source(
    		[&](boost::coroutines2::coroutine<int>::push_type& sink) {
    		int first = 1, second = 1;
    		sink(first);
    		sink(second);
    		for (int i = 0; i<8; ++i) {
    			int third = first + second;
    			first = second;
    			second = third;
    			sink(third);
    		}
    	});
    
    	for (auto i : source)
    	{
    		std::cout << i << " ";
    
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    输出:1 1 2 3 5 8 13 21 34 55

    两个协程交叉执行

    	boost::coroutines2::coroutine<int>::pull_type apull([](boost::coroutines2::coroutine<int>::push_type& apush)
    	{
    		for (int i = 0; i < 10; i++)
    		{
    			cout << "---------------------" << "coroutine 1" << endl;
    			apush(1);
    		}
    
    	}
    	);
    
    
    	boost::coroutines2::coroutine<int>::pull_type apull2([](boost::coroutines2::coroutine<int>::push_type& apush)
    	{
    
    		for (int i = 0; i < 10; i++)
    		{
    			cout << "---------------------" << "coroutine 2" << endl;
    			apush(2);
    		}
    
    	}
    	);
    
    	for (int i = 0; i < 10; ++i)
    	{
    		apull.get();
    		apull();
    		apull2.get();
    		apull2();
    	}
    	cout << "continue>>>" << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    输出:

    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    ---------------------coroutine 1
    ---------------------coroutine 2
    continue>>>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    python FastAPI 文件下载
    创建私有CA,我就用openSSL
    Java基础 --- Array和List互相转换
    ChatGPT-4 Alpha:OpenAI的革命性升级
    相机等效焦距
    彻底理解闭包实现原理
    Linux下安装配置各种软件和服务
    矩阵【线性代数系列(二)】
    卷积神经网络 作业
    OS>>多线程
  • 原文地址:https://blog.csdn.net/wangxudongx/article/details/134017232