协程和 C++ Boost库的Coroutine2

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

协程和 C++ Boost库的Coroutine2

  • 摘要
    • 为什么不是boost.coroutine?
  • 线程与协程
    • 为什么不介绍C++20标准的协程
    • C++协程与golang的goroutine
  • 二、使用步骤
    • 1.引入库
    • 2.核心类
    • 单个协程
    • 两个协程交叉执行


摘要

协程是一种轻量级的并发单位,相比于线程,它具有更小的内存占用和更高效的调度,适用于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。

协程和 C++ Boost库的Coroutine2_第1张图片

二、使用步骤

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 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;

输出:

---------------------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>>>

你可能感兴趣的:(1024程序员节,c++,协程,boost,coroutine)