协程的用例是什么?

协程的概念听起来很有趣,但我不知道在实际的生产环境中是否有意义? 协程的用例是什么,可以比其他方法更优雅,更简单或更有效地解决?

Mnementh asked 2020-07-03T20:05:53Z
7个解决方案
49 votes

一些良好的答案描述了协程。

但是对于一个实际的用例。 拿一个Web服务器。 它具有多个同时连接,并且它希望安排所有它们的读写。

这可以使用协程实现。 每个连接都是一个协程,它可以读取/写入少量数据,然后对调度程序进行“屈服”控制,并在我们循环访问所有可用连接时传递给下一个协程(执行相同的操作)。

Ali Afshar answered 2020-07-03T20:06:49Z
21 votes

其中很多,例如:

grep TODO *.c *.h | wc -l

上面的管道恰好是一个协程:grep命令生成一系列行,这些行将到达缓冲区,wc命令“将它们吃光”。 如果缓冲区已满,则grep“阻塞”直到缓冲区为空;如果缓冲区为空,则wc命令等待新输入。

关于协程的问题是,协程现在最常用于约束更严格的模式(如提到的Python生成器)或用作管道。

如果您想进一步了解它们,请参阅Wikipedia文章,尤其是有关协程和迭代器的文章。

Charlie Martin answered 2020-07-03T20:07:23Z
20 votes

我知道距提出问题已经过去了将近5年了,但是我很惊讶没有人提到游戏中的使用案例,在这些案例中,协程经常被用来计算时间。

为了在游戏中保持一致的帧速率(假设为60 fps),您需要在每个帧中执行大约16.6毫秒的代码。 其中包括物理模拟,输入处理,绘图/绘画。

可以说您的方法在每一帧中都执行。 如果您的方法花费很长时间并且最终跨越了多个帧,那么您将在游戏循环中错开其余计算,从而导致用户看到“刺痛”(帧速率突然下降)。

协程让您执行的是以某种方式对计算进行时间切片,以使其在每个帧中运行一点。

为此,协程本质上允许该方法将计算“产生”回“调用者”(在这种情况下为游戏循环),以便下次调用该方法时,该方法将从中断的位置恢复。

numan salati answered 2020-07-03T20:08:02Z
18 votes

真正的协程需要工具的支持-它们需要由编译器实现并由基础框架支持。

使用C#2.0中提供的“ yield return”关键字找到了协程的一个真实示例,该示例使您可以编写一种返回多个值以进行循环的方法。

但是,“收益回报”确实有局限性-该实现使用助手类来捕获状态,并且仅支持协程的特定情况作为生成器(迭代器)。

在更一般的情况下,协程的优势在于它们使某些基于状态的计算更易于表达和理解。与之相比,将状态机作为一组协程来实现,比更常见的方法更为优雅。 但是,这样做需要C#或Java中尚不存在的支持和工具。

Bevan answered 2020-07-03T20:06:20Z
12 votes

协程对于实现生产者/消费者模式很有用。

例如,Python在称为生成器的语言功能中引入了协程,该功能旨在简化迭代器的实现。

它们对于实现协作式多任务处理也很有用,其中每个任务都是协程,可产生调度程序/反应器。

ddaa answered 2020-07-03T20:08:31Z
10 votes

当系统具有两个或两个以上代码段(最自然的表示形式是一系列需要大量等待的连续步骤)时,协程可能会很有用。

例如,考虑具有LCD和小键盘用户界面以及调制解调器的设备,并且该设备需要使用调制解调器来周期性地呼叫和报告其状态,而与小键盘上的用户所进行的操作无关。 编写用户界面的最好方法可能是使用“ input_numeric_value(&CONV_SPEED_FORMAT,&conveyor_speed);”之类的函数。 当用户输入一个值时,它将返回,而处理通信的最佳方法可能是使用诸如“ wait_for_carrier();”之类的函数。 当设备连接或确定不连接时,它将返回。

如果没有协程,则必须使用状态机来实现UI子系统或调制解调器子系统。 使用协程可以使两个子系统以最自然的风格编写。 请注意,重要的是,任何子系统都不会花费很长时间而不将其置于“一致”状态并调用yield(),也不会调用yield()而不首先将其置于“一致”状态,但是通常不难满足这些要求 约束。

请注意,尽管可以使用成熟的多任务处理,但这需要在更改共享状态时随时随地使用锁。 由于协程切换器除了在yield()调用之外不会进行任何切换,因此任何一个例程都可以自由更改共享状态,只要它可以确保在下一个yield之前一切都按顺序进行,并且为其他例程准备更改状态“ 在“ yield()期间。

supercat answered 2020-07-03T20:09:06Z
6 votes

作为生产者/消费者系列中更具体的示例,像卑鄙的批处理报告程序这样的简单操作实际上可以使用协同例程。

该示例的关键提示是进行耗费大量时间的工作来消耗输入数据(例如,解析数据或在帐户上累积费用和付款),并且进行繁琐的工作来产生输出。 当您具有以下特征时:

  • 如果您可以在各个地方“散发”工作单元,则很容易组织/理解输入端代码。
  • 如果它可以“抓住”嵌套控制结构中的下一个工作单元,则同样很容易组织/理解输出端代码。

那么协程和队列都是您可以使用的不错的技术。

joel.neely answered 2020-07-03T20:09:45Z
translate from https://stackoverflow.com:/questions/303760/what-are-use-cases-for-a-coroutine