function(函數)routine(例程)coroutine (協程)
函數,例程以及協程都是指一系列的操作的集合。
函數(有返回值)以及例程(沒有返回值)也被稱作subroutine(子例程),因為它們的執行過程通常在父例程之前結束。
協程則有所不同,它是例程一般化的結果。
協程的執行過程允許被
- 中途掛起。(suspend)
- 稍后恢復運行。(resume)
協程通常用於實現
- 生成器。(generators)
- 異步函數。(asynchronous functions)
兩者的區別在於:
- 生成器的恢復執行由用戶顯式調用來決定。
- 異步函數的恢復執行由后台線程來決定。
boost::coroutines2::coroutine<>
boost::coroutines2::coroutine<>被用來實現協程。
它有兩個嵌套類型:pull_type和push_type。
pull_type可以從push_type那里接收並返回數據。
push_type可以把數據傳給pull_type。
#include <iostream>
#include <boost/coroutine2/coroutine.hpp>
using namespace std;
int main()
{
typedef boost::coroutines2::coroutine<int> coro_t;
int max = 8;
coro_t::pull_type source(
[&](coro_t::push_type& sink){
int first=1,second=1;
sink(first);
sink(second);
for(int i=0;i<max;++i){
int third=first+second;
first=second;
second=third;
sink(third);
}
});
for(auto i:source)
cout << i << " ";
cout << endl;
coro_t::push_type sink(
[&](coro_t::pull_type& source){
while(source){
cout << source.get() << " ";
source();
}
});
vector<int> v{1,1,2,3,5,8,13,21,34,55};
copy(begin(v),end(v),begin(sink));
}
// 1 1 2 3 5 8 13 21 34 55
// 1 1 2 3 5 8 13 21 34 55
- 這是一個使用協程實現斐波那契數列生成器的例子。
- 協程類的類型為boost::coroutines2::coroutine<int>。也就是說協程和主線程間相互傳遞的數據類型為int。
- pull_type類型對象source在構建時使用一個lambda來初始化。該lambda帶有一個push_type的引用參數sink。使用sink可以將數據傳回主線程。
C#同等功能的代碼如下
using System;
using System.Collections.Generic;
namespace Sample
{
class Fibonacci
{
public static void Main(string[] args)
{
IEnumerable<int> Source(int max)
{
int first = 1, second = 1;
yield return first;
yield return second;
for (int i = 0; i < max; ++i)
{
int third = first + second;
first = second;
second = third;
yield return third;
}
}
foreach (int i in Source(8))
Console.Write($"{i} ");
Console.WriteLine();
var v = new List<int> { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
void Sink()
{
foreach(int i in v)
{
Console.Write($"{i} ");
}
}
Sink();
}
}
}
// 1 1 2 3 5 8 13 21 34 55
// 1 1 2 3 5 8 13 21 34 55
