C# 中的协程
我正在寻找在 C# 中实现协同例程(用户调度线程)的方法。当使用 C++ 时,我使用的是 Fiber。我在互联网上看到 C# 中不存在光纤。我想获得类似的功能。
在 C# 中是否有任何“正确”的方法来实现协程?
我曾考虑过使用在调度程序线程上获取单个执行互斥体 + 1 的线程来实现此目的,该线程为每个协程释放此互斥体。但这似乎非常昂贵(它强制每个协程之间进行上下文切换)
我也看到了yield迭代器功能,但据我所知,你不能在内部函数中yield(仅在原始的ienumerator函数中)。所以这对我没什么好处。
I am looking at ways to implement co-routines (user scheduled threads) in c#. When using c++ I was using fibers. I see on the internet fibers do not exist in C#. I would like to get similar functionality.
Is there any "right" way to implement coroutines in c#?
I have thought of implementing this using threads that acquire a single execution mutex + 1 on scheduler thread which releases this mutex for each coroutine. But this seems very costly (it forces a context switch between each coroutine)
I have also seen the yield iterator functionality, but as I understand you can't yield within an internal function (only in the original ienumerator function). So this does me little good.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我相信新的 .NET 4.5\C# 5 的 async\await 模式应该可以满足您的需求。
我建议查看 http://channel9.msdn.com /Events/TechEd/Australia/Tech-Ed-Australia-2011/DEV411 了解更多信息。这是一个很棒的演示。
另外http://msdn.microsoft.com/en-us/vstudio/gg316360 有一些很棒的信息。
如果您使用的是较旧版本的 .NET,则可以使用适用于较旧版本的 .NET 的异步 CTP 并获得上线许可证,以便您可以在生产环境中使用它。以下是 CTP 的链接 http://www. microsoft.com/download/en/details.aspx?displaylang=en&id=9983
如果您不喜欢上述任一选项,我相信您可以遵循此处概述的异步迭代器模式。 http://www.microsoft.com/download/en /details.aspx?displaylang=en&id=9983
I believe with the new .NET 4.5\C# 5 the async\await pattern should meet your needs.
I suggest looking at http://channel9.msdn.com/Events/TechEd/Australia/Tech-Ed-Australia-2011/DEV411 for more info. It is a great presentation.
Also http://msdn.microsoft.com/en-us/vstudio/gg316360 has some great information.
If you are using an older version of .NET there is a Async CTP available for older .NET with a go live license so you can use it in production environments. Here is a link to the CTP http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=9983
If you don't like either of the above options I believe you could follow the async iterator pattern as outlined here. http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=9983
编辑:您现在可以使用这些:.net 中有 Fiber api 吗?< /a>
我相信您应该查看 .NET 的反应式扩展< /a>.例如协程可以使用迭代器和yield语句进行模拟。
不过,您可能也想阅读这个SO问题。
Edit: You can now use these: Is there a fiber api in .net?
I believe that you should look at the the Reactive Extensions for .NET. For example coroutines can be simulated using iterators and the yield statement.
However you may want to read this SO question too.
这里是一个使用线程实现协程的示例:
Here is an example of using threads to implement coroutines:
到了 2020 年,C# 发生了很多变化。我发表了一篇关于此主题的文章,异步使用 C# 8.0 和 IAsyncEnumerable 的协程:
It's 2020, lots of things have evolved in C#. I've published an article on this topic, Asynchronous coroutines with C# 8.0 and IAsyncEnumerable:
通道缺失的部分
管道是 golang 中相对于通道而言缺失的部分。通道实际上是 golang 的核心。通道是核心并发工具。如果您在 C# 中使用类似协程的东西,但使用线程同步原语(信号量、监视器、互锁等),那么它是不一样的。
几乎相同 - Pipelines,但在
8 年后才引入,并且 .Net Standard(.Net Framework / .Net Core)支持 Pipelines [https://blogs.msdn.microsoft.com/ dotnet/2018/07/09/system-io-pipelines-high-performance-io-in-net/]。管道优先用于网络处理。 Aspcore 现在跻身前 11 位明文吞吐量请求率之列 [https://www.techempower.com/benchmarks/#section=data-r16&hw=ph&test=plaintext]。
Microsoft 建议与网络流量交互的最佳实践:等待的网络字节(完成端口 IO)应将数据放入管道中,另一个线程应从管道中异步读取数据。许多管道可以串联用于字节流上的各种处理。 Pipeline 有一个读取器和一个写入器游标,虚拟缓冲区大小会导致写入器产生背压,以减少不必要的缓冲内存使用,通常会减慢网络流量。
Pipelines 和 Go Channels 之间存在一些关键差异。管道与 golang Channel 不同。管道是关于传递可变字节的,而不是用于使用内存引用(包括指针)发出信号的 golang 通道。最后,管道没有等效的
select
。(管道使用 Spans [https://adamsitnik.com/Span/],它已经存在了有一段时间,但现在在 .Net Core Spans 中进行了深度优化,显着提高了性能。.Net core 支持进一步提高了性能,但只是增量式的,因此 .Net Framework 的使用完全没问题),
因此管道应该是一个内置标准 。帮助替换.Net中的golang通道,但它们并不相同,并且在很多情况下管道不是答案。
Golang Channel 的直接实现
您需要小心(与 golang 一样),通过 .Net 通道传递的消息表明对象所有权的更改。这是只有程序员才能跟踪和检查的东西,如果你弄错了,你将有两个或多个线程在不同步的情况下访问数据。
Channels the missing piece
Pipelines are the missing piece relative to channels in golang. Channels are actually what make golang tick. Channels are the core concurrency tool. If you're using something like a coroutine in C# but using thread synchronisation primatives (semaphore, monitor, interlocked, etc..) then it's not the same.
Almost the same - Pipelines, but baked in
8 years later, and .Net Standard (.Net Framework / .Net Core) has support for Pipelines [https://blogs.msdn.microsoft.com/dotnet/2018/07/09/system-io-pipelines-high-performance-io-in-net/]. Pipelines are preferred for network processing. Aspcore now rates among the top 11 plaintext throughput request rates [https://www.techempower.com/benchmarks/#section=data-r16&hw=ph&test=plaintext].
Microsoft advises best practice for interfacing with network traffic: the awaited network bytes (Completion Port IO) should put data into a pipeline, and another thread should read data from the pipeline asynchronously. Many pipelines can be used in series for various processes on the byte stream. The Pipeline has a reader and a writer cursor, and the virtual buffer size will cause backpressure on the writer to reduce unnecessary use of memory for buffering, typically slowing down network traffic.
There are some critical differences between Pipelines and Go Channels. Pipelines aren't the same as a golang Channel. Pipelines are about passing mutable bytes rather than golang channels which are for signalling with memory references (including pointers). Finally, there is no equivalent
select
with Pipelines.(Pipelines use Spans [https://adamsitnik.com/Span/], which have been around for a little while, but now are optimised deeply in .Net Core. Spans improve performance significantly. The .Net core support improves performance further but only incrementally, so .Net Framework use is perfectly fine. )
So pipelines are a built-in standard should help replace golang channels in .Net, but they are not the same, and there will be plenty of cases where pipelines are not the answer.
Direct Implementations of Golang Channel
You would need to be careful (as with golang) that passed messages via a .Net Channel indicate a change of ownership over an object. This is something only a programmer can track and check, and if you get it wrong, you'll two or more threads accessing data without synchronisation.
您可能对这是一个隐藏协程用法的库感兴趣。例如读取文件:
该库使用一个线程来运行所有协程,并允许调用任务来进行真正的异步操作。例如,调用另一个方法作为协程(也称为其返回值的屈服)
You may be interested in this is a library that hides the usage of coroutines. For example to read a file:
This library uses one thread to run all coroutines and allow calling the task for the truly asynchronous operations. For example to call another method as a coroutine (aka yielding for its return