2010-04-08 4 views
39

Я ищу способы реализовать совместные подпрограммы (пользовательские потоки) в C#. При использовании C++ я использовал волокна. Я вижу, что в интернет-волокнах нет на C#. Я хотел бы получить аналогичную функциональность.Coroutines in C#

Есть ли «правильный» способ реализовать сопрограммы в C#?

Я подумал об этом, используя потоки, которые получают один мьютез выполнения + 1 в потоке планировщика, который освобождает этот мьютекс для каждой сопрограммы. Но это кажется очень дорогостоящим (он переключает контекст между каждой сопрограммой)

Я также видел функциональность итератора вывода, но, как я понимаю, вы не можете выполнить внутреннюю функцию (только в исходной функции ienumerator). Так что мне это мало пользы.

+0

Ссылка: http://blogs.msdn.com/larryosterman/archive/2005/01/05/347314.aspx –

+0

Вы можете найти это полезно/интересно: https://github.com/bvanderveen/coroutine – gsscoder

ответ

12

Edit: Теперь вы можете использовать эти: Is there a fiber api in .net?

Я считаю, что вы должны смотреть на на Reactive Extensions for .NET. Например, заявление coroutines can be simulated using iterators and the yield.

Однако вы можете также прочитать это SO question.

+0

Блоки Iterator больше не актуальны с Rx 2.0, что теперь обеспечивает перегрузки 'Observable.Create', которые принимают функцию' Task'-return, тем самым объединяя создание наблюдаемого (call/cc) с родными сопрограммами C# 5 (_async/await_). Это можно определить как «асинхронный итератор». См. [этот поток] (http://social.msdn.microsoft.com/ Форумы/en-US/6e0ead42-4d89-429d-b6a8-d422cf673390/how-is-the-the-experimental-createiterator-redundant-with-net-45? Forum = rx) для получения дополнительной информации и [мой пост в блоге] (http: //davesexton.com /blog/post/async-iterators.aspx) для сравнения. –

+0

@DaveSexton - не стесняйтесь редактировать ответ –

+0

Хм, хорошо спасибо. Я довольно новичок в SO, и я не был уверен в вики-этикете. Сначала я буду читать «правила». –

6

Here является примером использования потоков для реализации сопрограмм:

Так я обманываю. Я использую потоки, но я только пусть один из них запускается за раз. Когда I создайте сопрограмму, я создаю нить, , а затем сделаю некоторое подтверждение связи, которое заканчивается с вызовом Monitor.Wait(), который блокирует поток coroutine - он не будет бежать больше, пока он не будет разблокирован. Когда пришло время позвонить в сопрограмму, Я выполняю эстафетную передачу обслуживания, которая заканчивается блокировкой вызывающего потока , а также исполняемой нити coroutine. Тот же вид передачи обслуживания на обратном пути.

Эти передачи являются довольно дорогими, по сравнению с другими реализациями. Если вам нужна скорость, вам нужно будет написать свой собственный конечный автомат, и избежать всех этих переключений контекста. (Или вы хотите использовать волоконно-оптическую связь - переключение волокон довольно дешево.) Но если вы хотите выразительный код , я думаю, что сопрограммы содержат некоторое обещание.

+3

Одно ограничение с использованием потоков заключается в том, что (как и в Winforms и WPF, я считаю) элементы управления формы, созданные потоком 'Larry', не могут быть доступны нитью' Moe', даже если нить 'Larry' ничего не делает с формой и будет заблокирован до тех пор, пока 'Moe' ничего не сделает с этим. Если две сопрограммы могут работать в одном и том же потоке ОС, они могут совместно использовать ресурсы, которые в противном случае могут использоваться только создающим потоком. – supercat

10

Я верю в новый .NET 4.5 \ C# 5, шаблон async \ await должен соответствовать вашим потребностям.

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

Предлагаю посмотреть на http://channel9.msdn.com/Events/TechEd/Australia/Tech-Ed-Australia-2011/DEV411 для получения дополнительной информации. Это отличная презентация.

Также http://msdn.microsoft.com/en-us/vstudio/gg316360 содержит отличную информацию.

Если вы используете более старую версию .NET, для Asus CTP доступен более старый .NET с живой лицензией go, чтобы вы могли использовать его в производственных средах.Вот ссылка на 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

0

Возможно, вас заинтересует this - это библиотека, которая скрывает использование сопрограмм. Например, чтобы прочитать файл:

//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(); 

Эта библиотека использует один поток для выполнения всех сопрограмм и позволяют называть задачу по-настоящему асинхронных операций. Например, для вызова другого метода как сопрограммы (он же приносит его возвращения

//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;