Как вы можете делать Co-рутины, используя C #? - PullRequest
10 голосов
/ 22 марта 2010

В python ключевое слово yield можно использовать как в контекстах push, так и в pull, я знаю, как сделать контекст pull в c #, но как мне добиться push. Я публикую код, который я пытаюсь повторить в C # из Python:

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"

Ответы [ 7 ]

14 голосов
/ 22 марта 2010

Если вы хотите получить «наблюдаемую коллекцию», то есть коллекцию, которая направляет результаты вам, а не позволяет потребителю получать их - тогда вы, вероятно, захотите взглянуть на расширения Reactive Framework. Вот статья об этом:

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

Теперь, как вы заметили, вы можете легко создавать итераторы в стиле «push» и «pull», если у вас есть сопрограммы. (Или, как указывает Томас, вы также можете создавать их с продолжениями.) В текущей версии C # у нас нет настоящих сопрограмм (или продолжений). Тем не менее, мы очень обеспокоены болью, которую пользователи испытывают при асинхронном программировании .

Реализация сопрограмм на основе волокон в качестве первоклассной языковой функции - это один из методов, который может быть использован для облегчения асинхронного программирования, но это лишь одна из возможных идей многих, которые мы сейчас исследуем. Если у вас действительно хороший сценарий, когда сопрограммы работают лучше, чем что-либо еще, включая реактивную структуру, тогда я бы хотел услышать больше об этом. Чем больше у нас реальных данных о реальных проблемах, с которыми сталкиваются люди при асинхронном программировании, тем больше у нас шансов найти хорошее решение. Спасибо!

ОБНОВЛЕНИЕ: Недавно мы объявили, что добавляем сопрограммированные асинхронные потоки управления в следующую версию C # и VB. Вы можете попробовать сами с нашей предварительной версией Community Technology Preview, которую вы можете скачать здесь .

7 голосов
/ 22 марта 2010

C # не имеет общих сопрограмм. Общая подпрограмма - это когда подпрограмма имеет свой собственный стек, то есть она может вызывать другие методы, и эти методы могут «выдавать» значения. Реализация общих подпрограмм требует создания некоторых умных вещей со стеками, возможно вплоть до включения кадров стека (скрытых структур, которые содержат локальные переменные) в куче. Это может быть сделано, некоторые языки делают это (например, схема), но сделать это правильно довольно сложно. Кроме того, многим программистам трудно понять эту функцию.

Общие подпрограммы можно эмулировать с потоками. Каждый поток имеет свой собственный стек. В настройке сопрограммы оба потока (начальный вызывающий и поток для подпрограммы) будут чередовать управление, они никогда не будут работать одновременно. Механизм «yield» представляет собой обмен между двумя потоками, и поэтому он является дорогостоящим (синхронизация, циклическая передача по ядру ОС и планировщику ...). Кроме того, существует много места для утечек памяти (сопрограмма должна быть явно «остановлена», иначе ожидающий поток будет зависать вечно). Таким образом, это делается редко.

C # предоставляет функцию рутинной обработки, называемую iterators . Компилятор C # автоматически преобразует код итератора в определенный класс состояний, а локальные переменные становятся полями классов. Выход на уровне ВМ - это равнина return. Такая вещь выполнима до тех пор, пока «yield» выполняется из самого кода итератора, а не из метода, который вызывает код итератора. Итераторы C # уже охватывают множество вариантов использования, и разработчики C # не хотели идти дальше по пути к продолжениям . Некоторые саркастичные люди стремятся заявить, что реализация полнофункциональных продолжений помешала бы C # быть столь же эффективным, как его заклятый враг Java (эффективные продолжения возможны, но это требует довольно большой работы с GC и JIT-компилятором).

3 голосов
/ 22 марта 2010

спасибо @NickLarsen, вы помогли мне вспомнить новый материал, представленный MS, интерфейс IObservable.

ссылка http://msdn.microsoft.com/en-us/library/dd783449(VS.100).aspx

3 голосов
/ 22 марта 2010
1 голос
/ 08 июля 2010

На самом деле .NET не делает «неправильных предположений» о сходстве потоков, фактически полностью отделяет понятие потока уровня .NET от потока уровня ОС.

То, что вам нужно сделать, это связать логическое состояние потока .NET с вашим волокном (для этого вам нужен API-интерфейс хостинга CLR, но вам не нужно самим писать хост, вы можете использовать те, которые нужны из вашегоприложения) и все, отслеживание блокировки, обработка исключений снова работает нормально.

Пример можно найти здесь: http://msdn.microsoft.com/en-us/magazine/cc164086.aspx

Кстати, Mono 2.6 содержит низкоуровневую поддержку сопрограмм и может использоваться длялегко реализовать все примитивы более высокого уровня.

0 голосов
/ 22 апреля 2014

Ну, я попробовал разработать полную библиотеку для управления сопрограммами только с одним потоком.Сложно было вызывать сопрограммы внутри сопрограмм ... и возвращать параметры, но в итоге я достиг довольно хорошего результата здесь .Единственное предупреждение состоит в том, что блокирующие операции ввода-вывода должны выполняться через задачи, а все «возврат» должен быть заменен на «возврат возврата».С сервером приложений, основанным на этой библиотеке, я смог почти удвоить количество запросов, сделанных с помощью стандартного async / await на основе IIS.(Ищите Node.Cs и Node.Cs.Musicstore на github, чтобы попробовать его дома)

0 голосов
/ 04 июля 2010

Я хотел бы увидеть API на основе оптоволокна для .Net.

Я пытался использовать нативный API-интерфейс волокна в C # через p / invoke некоторое время назад, но поскольку обработка исключений во время выполнения (неверно) делает предположения на основе потоков, вещи ломались (плохо), когда возникали исключения.

Одним "убийственным приложением" для сопрограмм на основе оптоволокна является программирование игр; для определенных типов ИИ требуется «легкая» нить, которую вы можете использовать по желанию. Например, деревья поведения в игре требуют способности «пульсировать» код решения в каждом кадре, что позволяет AI-коду совместно возвращаться вызывающей стороне, когда секция решения поднимается. Это возможно реализовать с помощью жестких потоков, но намного, намного сложнее.

Таким образом, хотя истинные сценарии использования оптоволокна не являются общепринятыми, они определенно существуют, и небольшая ниша из нас .Net-кодировщиков сильно приветствовала бы, если бы существующие ошибки в оптоволоконной подсистеме были устранены.

...