Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coroutines in C#

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.

like image 921
eyal Avatar asked Apr 08 '10 11:04

eyal


People also ask

What is a coroutines used for?

A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously. Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages.

How are coroutines different from threads?

Coroutines vs Threads Comparison Table. A coroutine is a program, one of the cooperative types of subprograms which allows to pause and resume at the time of execution. Threads, on the other hand, are built-in processes. Coroutines are a form of sequential processing, and one is executed at a time.

How coroutine is implemented?

A coroutine internally uses a Continuation class to capture the contexts for its execution. Then the dynamic aspect is modeled as a Job class. The use of async usually creates a Deferred job, which is a subclass of the Job class. The CoroutineContext type is required for a coroutine to execute.

Does C++ support coroutines?

The main idea of coroutines is to have a function that preserves a state while releasing control back to the caller. Coroutines in C++ are a complex beast. The coroutine implementer should manage the frame to be created when yielding out, but we used an external library that manages this for us.


6 Answers

I believe with the new .NET 4.5\C# 5 the async\await pattern should meet your needs.

async Task<string> DownloadDocument(Uri uri)
{  
  var webClient = new WebClient();
  var doc = await webClient.DownloadStringTaskAsync(url);
  // do some more async work  
  return doc;  
}  

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

like image 182
Aaron Stainback Avatar answered Sep 27 '22 14:09

Aaron Stainback


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.

like image 27
Preet Sangha Avatar answered Sep 27 '22 14:09

Preet Sangha


Here is an example of using threads to implement coroutines:

So I cheat. I use threads, but I only let one of them run at a time. When I create a coroutine, I create a thread, and then do some handshaking that ends with a call to Monitor.Wait(), which blocks the coroutine thread — it won’t run anymore until it’s unblocked. When it’s time to call into the coroutine, I do a handoff that ends with the calling thread blocked, and the coroutine thread runnable. Same kind of handoff on the way back.

Those handoffs are kind of expensive, compared with other implementations. If you need speed, you’ll want to write your own state machine, and avoid all this context switching. (Or you’ll want to use a fiber-aware runtime — switching fibers is pretty cheap.) But if you want expressive code, I think coroutines hold some promise.

like image 45
SLaks Avatar answered Sep 27 '22 14:09

SLaks


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

  • https://codereview.stackexchange.com/questions/32500/golang-channel-in-c - this is some custom code, and not complete.

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.

like image 38
Kind Contributor Avatar answered Sep 26 '22 14:09

Kind Contributor


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:

In the C# world, they (coroutines) have been popularized by Unity game development platform, and Unity uses IEnumerator-style methods and yield return for that.

Prior to C# 8, it wasn't possible to combine await and yield return within the same method, making it difficult to use asynchrony inside coroutines. Now, with the compiler's support for IAsyncEnumerable, it can be done naturally.

like image 22
noseratio Avatar answered Sep 24 '22 14:09

noseratio


You may be interested in this is a library that hides the usage of coroutines. For example to read a file:

//Prepare the file stream
FileStream sourceStream = File.Open("myFile.bin", FileMode.OpenOrCreate);
sourceStream.Seek(0, SeekOrigin.End);

//Invoke the task
yield return InvokeTaskAndWait(sourceStream.WriteAsync(result, 0, result.Length));

//Close the stream
sourceStream.Close();

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

//Given the signature
//IEnumerable<string> ReadText(string path);

var result = new Container();
yield return InvokeLocalAndWait(() => _globalPathProvider.ReadText(path), container);
var data = container.RawData as string;
like image 42
Kendar Avatar answered Sep 27 '22 14:09

Kendar