Coroutines в С#
Я рассматриваю способы реализации совлокальных подпрограмм (пользовательских потоков) в С#. При использовании С++ я использовал волокна. Я вижу, что в интернет-волокнах нет на С#. Я хотел бы получить аналогичную функциональность.
Есть ли какой-либо "правильный" способ реализовать сопрограммы в С#?
Я подумал об этом, используя потоки, которые обретают один мьютекс исполнения + 1 в потоке планировщика, который освобождает этот мьютекс для каждой сопрограммы. Но это кажется очень дорогостоящим (он переключает контекст между каждой сопрограммой)
Я также видел функциональность итератора вывода, но, как я понимаю, вы не можете выполнить внутреннюю функцию (только в исходной функции ienumerator). Так что мне это мало пользы.
Ответы
Ответ 1
Изменить: теперь вы можете использовать их: Есть ли api файл в .net?
Я считаю, что вы должны посмотреть на Reactive Extensions for.NET. Например, сопрограммы могут быть смоделированы с использованием итераторов и утверждения yield.
Однако вы можете также прочитать этот вопрос SO.
Ответ 2
Я считаю, что с новым .NET 4.5\С# 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, для Ascc 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
Ответ 3
Здесь приведен пример использования потоков для реализации сопрограмм:
Так что я обманываю. Я использую потоки, но я только пусть один из них работает одновременно. Когда я создать сопрограмму, создать поток, и затем выполните какое-то рукопожатие, которое заканчивается с вызовом Monitor.Wait(), который блокирует резьбу coroutine - это не будет работать до тех пор, пока не разблокируется. когда его время, чтобы позвонить в сопрограмму, Я выполняю передачу обслуживания, которая заканчивается вызывающий поток заблокирован, и Выполняемая резьба coroutine. Такой же передачи обслуживания на обратном пути.
Эти передачи являются дорогими, по сравнению с другими реализациями. Если вам нужна скорость, вы хотите напишите свой собственный автомат и избегайте всего этого переключения контекста. (Или вы хотите использовать время выполнения - переключение волокон довольно дешево.) Но если вы хотите выразительных код, я думаю, что сопрограммы обещание.
Ответ 4
Вам может быть интересно 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;