【问题标题】:How can you do Co-routines using C#?如何使用 C# 执行协同例程?
【发布时间】:2011-01-30 09:36:47
【问题描述】:

在 python 中,yield 关键字可以在推送和拉取上下文中使用,我知道如何在 c# 中执行拉取上下文,但我将如何实现推送。我发布了我试图从 python 复制到 c# 中的代码:

def coroutine(func):
  def start(*args,**kwargs):
    cr = func(*args,**kwargs)
    cr.next()
    return cr
  return start

@coroutine
def grep(pattern):
  print "Looking for %s" % pattern
  try:
    while True:
      line = (yield)
      if pattern in line:
        print line,
  except GeneratorExit:
    print "Going away. Goodbye"

【问题讨论】:

  • Eric Lippert 在某处有一篇博文
  • 考虑更多地使用制表符/空格来格式化你的代码。
  • 制表符格式...确实是必要的,不是时间问题,是 python 问题。
  • 只是根据要求改进了格式:)
  • 现在已经旧了,但是调用 IronPython 是否可以解决这个问题?

标签: c# python system.reactive coroutine


【解决方案1】:

如果您想要的是一个“可观察的集合”——也就是说,一个将结果推送给您而不是让消费者拉取结果的集合——那么您可能想要研究 Reactive Framework 扩展。这是一篇关于它的文章:

http://www.infoq.com/news/2009/07/Reactive-Framework-LINQ-Events

现在,正如您所注意到的,如果您有可用的协程,则可以轻松构建“push”和“pull”样式的迭代器。 (或者,正如 Thomas 指出的那样,您也可以使用延续来构建它们。)在当前版本的 C# 中,我们没有真正的协程(或延续)。但是,我们非常关心用户对异步编程的感受。

将基于 Fiber 的协程实现为一流的语言功能是一种可能用于使异步编程更容易的技术,但这只是我们目前正在研究的许多想法中的一种。如果你有一个非常棒的场景,协程比其他任何东西都做得更好——包括反应式框架——那么我很想听听更多关于它的信息。关于人们在异步编程中面临的实际问题,我们掌握的数据越真实,我们就越有可能提出一个好的解决方案。谢谢!

更新:我们最近宣布,我们将在下一版本的 C# 和 VB 中添加类似协程的异步控制流。您可以使用我们的社区技术预览版自行尝试,您可以下载here

【讨论】:

  • 一种这样的场景是事件驱动模拟(Simula 风格)。我有一个使用 Win32 光纤的项目,但我仍然无法移植到 .NET
  • 我认为 C# 中的异步编程很棒。不过,我喜欢 F# 中 Erlang 风格的 MailboxProcessor。至于协程,我觉得非常有趣。我知道它们是旧技术,并且在引入线程时被一扫而空,但我喜欢这样的想法,即我确切地知道例程何时执行以及何时将控制权传回。我发现线程的主要问题是缺乏控制和创建它们的一般沉重。然而,它们确实提供了一个很好的思想抽象水平,只需要很少的努力来实现:)
  • 谢谢埃里克。听起来很有希望!
【解决方案2】:

C# 没有 general 协程。通用协程是协程有自己的堆栈的地方,即它可以调用其他方法并且这些方法可以“产生”值。通用协程的实现需要用堆栈做一些聪明的事情,可能包括在堆上分配堆栈帧(包含局部变量的隐藏结构)。这可以做到,某些语言会这样做(例如 Scheme),但要正确地做到这一点有些棘手。此外,许多程序员发现该功能难以理解。

一般的协同程序可以用线程来模拟。每个线程都有自己的堆栈。在协同程序设置中,两个线程(初始调用者和协同程序的线程)将交替控制,它们永远不会真正同时运行。然后,“yield”机制是两个线程之间的交换,因此它很昂贵(同步,通过操作系统内核和调度程序的往返......)。此外,还有很大的内存泄漏空间(协程必须明确“停止”,否则等待的线程将永远停留)。因此,很少这样做。

C# 提供了一个名为 iterators 的低级协同程序功能。 C# 编译器自动将迭代器代码转换为特定的状态类,局部变量成为类字段。然后,在 VM 级别,屈服是一个普通的return。只要“yield”是从迭代器代码本身执行的,而不是从迭代器代码调用的方法中执行,这样的事情是可行的。 C# 迭代器已经涵盖了许多用例,而 C# 设计者不愿意在 continuations 的道路上走得更远。一些讽刺的人热衷于声明,实现全功能的延续会阻止 C# 像它的宿敌 Java 一样高效(高效的延续是可行的,但这需要 GC 和 JIT 编译器进行相当多的工作)。

【讨论】:

  • 不错的答案。我想我找到了我想用 C# 做的事情,IObservable。关于堆栈的那些东西,在幕后的 Python 是否会这样做,因为我不认为它会这样做。它使用香草C。但我不确定。我试图避免所有线程的使用,因此我对协程根感兴趣。我发现如果我可以完全控制我的编程,并且我有避免线程的工具,为什么不试试呢。协程的东西应该是一种享受,只要它包裹在 IObservable fake 中:)
  • Java 高效...:) 抱歉让我笑了。我记得使用 JBoss 做了一个解决方案。这个东西不会释放对象,我们告诉我们的最终客户(T.U.I. --- Thomas Cook)他需要不时打开和关闭它。 :)
  • 如果你不喜欢 Java,效率方面,那么你很可能对 C# 也不是很满意。它们在这方面非常相似。实际上,它们在每个视图中都非常相似。
  • 非常真实,我与两者都合作过,他们确实感觉相似。与 Java 相比,我使用 .Net 获得了更好的内存足迹。我认为这与确定性处置有关。如果可以选择,我不会使用任何一个。但我必须使用行业要求的东西。我会使用 F# 或 python。
【解决方案3】:

【讨论】:

  • 我知道可以做到,将状态保存为对象并调用它的方法,但是直接的协同程序呢。
  • 是的,我看到了,而且我已经查看了正在介绍的 IObservable 内容,等等,我刚刚经历了一个“点击时刻”:)
【解决方案4】:

感谢@NickLarsen,你帮助我记住了 MS 引入的新东西,IObservable 接口。

链接http://msdn.microsoft.com/en-us/library/dd783449(VS.100).aspx

【讨论】:

    【解决方案5】:

    实际上 .NET 并没有对线程亲和性做出“错误假设”,实际上它完全将 .NET 级线程的概念与操作系统级线程分离。

    您要做的是将逻辑 .NET 线程状态与您的纤程关联(为此您需要 CLR 托管 API,但您不需要自己编写主机,您可以直接使用您自己的应用程序所需的那些)一切,锁定跟踪,异常处理再次正常工作。

    可以在此处找到示例:http://msdn.microsoft.com/en-us/magazine/cc164086.aspx

    顺便说一句,Mono 2.6 包含低级协程支持,可用于轻松实现所有更高级别的原语。

    【讨论】:

      【解决方案6】:

      我希望看到基于光纤的 .Net API。

      不久前,我尝试通过 p/invoke 在 C# 中使用本机 Fiber API,但由于运行时的异常处理(错误地)做出了基于线程的假设,所以当异常发生时,事情就坏了(严重)。

      基于 Fiber 的协程 API 的一个“杀手级应用”是游戏编程;某些类型的 AI 需要一个“轻量级”线程,您可以随意对它进行时间切片。例如,游戏行为树需要能够在每一帧“脉冲”决策代码,从而允许 AI 代码在决策切片启动时协同返回给调用者。这可以通过硬线程来实现,但要复杂得多。

      因此,虽然真正的光纤用例不是主流,但它们肯定存在,如果解决了光纤子系统中现有的错误,我们中的一小部分 .Net 编码人员会欢呼雀跃。

      【讨论】:

        【解决方案7】:

        好吧,我尝试开发一个完整的库来管理只有一个线程的协程。困难的部分是在协程中调用协程......并返回参数,但最后我得到了一个很好的结果here。唯一的警告是阻塞 I/O 操作必须通过任务进行,并且所有“return”必须替换为“yield return”。 使用基于此库的应用程序服务器,我能够将使用基于 IIS 的标准 async/await 发出的请求增加近一倍。 (在github上找Node.Cs和Node.Cs.Musicstore在家试试)

        【讨论】:

          猜你喜欢
          • 2021-08-27
          • 2019-04-12
          • 2016-03-29
          • 2019-09-17
          • 2018-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多