Coroutines
От: DemAS http://demas.me
Дата: 24.02.09 11:58
Оценка: 5 (1)
Сегодня, совершенно неожиданно для себя, открыл Coroutines.
Пример их использования, который я нашел:

import multitask
import time

def c1():
    for i in range(3):
       print 'c1'
       yield i

def c2():
    for i in range(3):
       print 'c2'
       yield i

multitask.add(c1())
multitask.add(c2())
multitask.run()


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

Собственно, два вопроса:

1. Буду благодарен за пример проблемы, в решении которой coroutines не
притянуты за уши.

Я нашел вот это: http://c2.com/cgi/wiki?OddWordProblem
И решение: http://c2.com/cgi/wiki?OddWordProblemSolutions.

В решении на C# coroutines я вообще не увидел

        using System;
    using System.IO;
    using System.Collections;


    public class OddWordProblem {
    [STAThread]
    static void Main(string[] args) {
        StreamWriter output = new StreamWriter(args[1]);
        new OddWordProblem().Solve(new StreamReader(args[0]), output);
        output.Flush();
    }


    ArrayList currentWord = new ArrayList();
    char aSeparator;
    bool isForward=true;
    bool isWordEnded=false;


    void Solve(StreamReader theInput, StreamWriter theOutput) {
        int nextChar;
        while ((nextChar = theInput.Read())!=-1) {
        char aChar = (char)nextChar;
        if(aChar==' '||aChar=='.')EndOfWord(theOutput, aChar);
        else MiddleOfWord(theOutput, aChar);
        }
        theOutput.Write(aSeparator);
    }
    void MiddleOfWord(StreamWriter theOutput, char aChar) {
        if(isWordEnded) {
        isWordEnded = false;
        isForward = !isForward;
        theOutput.Write(aSeparator);
        }
        currentWord.Add(aChar);
    }
    void EndOfWord(StreamWriter output, char nextChar) {
        if(!isForward)currentWord.Reverse();
        foreach(char aChar in currentWord)
        output.Write(aChar);
        aSeparator = nextChar;
        currentWord = new ArrayList();
        isWordEnded = true;
    }
    }


Мы всего лишь засунули символы в буфер и вызвали метод .Reverse(). Или я
чего то не понимаю?

2. Вопрос по реализации. Если я правильно понимаю, между вызовами coroutine
ее состояние(локальные переменные и точка возврата) должна где-то
сохраняться. Где она сохраняется? Неужели в стеке?
Posted via RSDN NNTP Server 2.1 beta
Re: Coroutines
От: WolfHound  
Дата: 24.02.09 13:38
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>1. Буду благодарен за пример проблемы, в решении которой coroutines не притянуты за уши.


  ReadAllLinesLazy(fileName : string) : System.Collections.Generic.IEnumerable[string]
  {
    using (file = IO.File.OpenText(fileName))
    {
      def loop()
      {
        def line = file.ReadLine();
        when (line != null)
        {
          yield line;
          loop();
        }
      }
      loop();
    }
  }

  Test() : void
  {
    foreach (line in ReadAllLinesLazy("ФайлоНаДесятьГигабайт"))
    {
      WriteLine(line);
    }
  }


DAS>В решении на C# coroutines я вообще не увидел

Ну так это первый C#... там корутин нету. Во втором есть yield return.

DAS>2. Вопрос по реализации. Если я правильно понимаю, между вызовами coroutine ее состояние(локальные переменные и точка возврата) должна где-то сохраняться. Где она сохраняется? Неужели в стеке?

Зависит от реализации.
В случае C# и Nemerle генерируется некий класс который и хранит состояние.
В других реализациях может быть иначе вплоть до инлайна корутины.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Coroutines
От: R.K. Украина  
Дата: 24.02.09 13:45
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>Собственно, два вопроса:


DAS>1. Буду благодарен за пример проблемы, в решении которой coroutines не

DAS>притянуты за уши.

Тоже не так давно открыл для себя их, но в однопоточной среде и С++
Вот пара примеров:
  • Генератор простых чисел
    Автор: R.K.
    Дата: 29.05.08
    . Последняя публичная версия: http://uxn.livejournal.com/1333.html. Еще более оптимизированная версия использовалась для решения проблемы PRIME1 за 0.04 сек.
  • Внешняя сортировка строк огромных файлов
    Автор: R.K.
    Дата: 28.01.09


    DAS>Я нашел вот это: http://c2.com/cgi/wiki?OddWordProblem

    DAS>И решение: http://c2.com/cgi/wiki?OddWordProblemSolutions.

    DAS>В решении на C# coroutines я вообще не увидел


    Боюсь решение данной проблемы как раз притянуто за уши к генераторам.

    DAS>2. Вопрос по реализации. Если я правильно понимаю, между вызовами coroutine

    DAS>ее состояние(локальные переменные и точка возврата) должна где-то
    DAS>сохраняться. Где она сохраняется? Неужели в стеке?

    А почему бы и нет? Вот в реализации на С++, где создается объект класса генератора, там и хранится состояние.
  • You aren't expected to absorb this
    Re[2]: Coroutines
    От: DemAS http://demas.me
    Дата: 24.02.09 14:13
    Оценка:
    Твоя coroutine похожа на generator.

    http://c2.com/cgi/wiki?CoRoutine.

    Coroutines are functions or procedures that save control state between calls (as opposed to, but very similar to, Generators, such as Random Number Generators, that save data state between calls).


    Может я не прав, но мне кажется, что у тебя генератор.
    Posted via RSDN NNTP Server 2.1 beta
    Re: Coroutines
    От: z00n  
    Дата: 24.02.09 15:09
    Оценка: 17 (2)
    Здравствуйте, DemAS, Вы писали:

    DAS>1. Буду благодарен за пример проблемы, в решении которой coroutines не

    DAS>притянуты за уши.
    В луа, например, корутины обыденная часть языка, и есть много чего почитать от научных статей до конкретных паттернов применения:
    Revisiting Coroutines (оч. рекомендую)
    Token Filters(типичный пример применения)
    PIL: Coroutine Basics
    http://lua-users.org/wiki/FiltersSourcesAndSinks
    http://lua-users.org/wiki/CoroutinesAsEventHandlers
    http://lua-users.org/wiki/CoroutinesAsConnectionHandlers
    http://lua-users.org/wiki/FunWithCoroutines

    У меня обычный случай применения: либо итератор для разлапистой структуры данных, либо низкоуровневый кирпич для чего-нибудь более интересного. На основе корутин (по крайней мере если они кооперативные треды как в луа) можно реализовать более высокоуровневый набор примитивов, например CSPOCCAMLimboStackless Python.
    Events vs. Threads
    Bell Labs and CSP Threads

    DAS>2. Вопрос по реализации. Если я правильно понимаю, между вызовами coroutine

    DAS>ее состояние(локальные переменные и точка возврата) должна где-то
    DAS>сохраняться. Где она сохраняется? Неужели в стеке?
    В луа корутина — просто кооперативный тред со своим стеком (примерно как в erlang). Занимает примерно 1K(тоже примерно как в erlang) — можно завести их сотни тысяч.

    Хороший обзор методов реализации есть в документации luajit:
    Context Switching Methods
    Вот еще известный документ:
    Coroutines in C
    Re[3]: Coroutines
    От: R.K. Украина  
    Дата: 24.02.09 15:24
    Оценка:
    Здравствуйте, DemAS, Вы писали:


    DAS>Твоя coroutine похожа на generator.


    DAS>http://c2.com/cgi/wiki?CoRoutine.


    DAS>

    DAS>Coroutines are functions or procedures that save control state between calls (as opposed to, but very similar to, Generators, such as Random Number Generators, that save data state between calls).


    DAS>Может я не прав, но мне кажется, что у тебя генератор.


    Из статьи я понял, что корутины это некие программные компоненты, передающие друг другу право на исполнение, исполняющиеся перемежающимся способом. Генераторы же просто выдают некоторые значения, когда их вызывают, пока не завершатся.
    А еще там написано:

    Generators are also a generalisation of subroutines, but with at first sight less expressive power than coroutines; since generators are primarily used to simplify the writing of iterators, the yield statement in a generator does not specify a coroutine to jump to, but rather passes a value back to a parent routine. However, it is still possible to implement coroutines on top of a generator facility, with the aid of a top-level dispatcher routine that passes control explicitly to child generators identified by tokens passed back from the generators

    Т.е. тот код, что ты привел в корне (на Эрланге?), как раз использует генераторы, а их совместная работа обеспечивается многозадачным диспатчером верхнего уровня.
    You aren't expected to absorb this
    Re[4]: Coroutines
    От: DemAS http://demas.me
    Дата: 24.02.09 16:28
    Оценка:
    "R.K." <42491@users.rsdn.ru> writes:

    > Т.е. тот код, что ты привел в корне (на Эрланге?), как раз использует

    > генераторы, а их совместная работа обеспечивается многозадачным
    > диспатчером верхнего уровня.

    На Python.
    Глава из книги Expert Python Programming.
    Там этот пример приводится в разделе про coroutines.
    Согласен, что пример неудачный — поэтому и ищу более понятный.
    Твой код посмотрю чуть позже — просто у меня с C++ не супер и для изучения
    нужна более спокойная обстановка.
    Posted via RSDN NNTP Server 2.1 beta
    Re: Coroutines
    От: Alexander G Украина  
    Дата: 01.03.09 13:02
    Оценка:
    Здравствуйте, DemAS, Вы писали:

    DAS>1. Буду благодарен за пример проблемы, в решении которой coroutines не

    DAS>притянуты за уши.

    Сталкивался с тамим, не знаю на сколько за уши:

    У нас допустим есть большой блок данных, который нужно обработать несколькими алгоритмами и выбрать лучший результат. Причём алгоритмы уже есть:
    result alg1(ISequentialStream * data);
    result alg2(ISequentialStream * data);
    ...
    result algN(ISequentialStream * data);

    Чтобы не читать этот большой блок данных N раз, а сделать всё в один проход (допустим, блок на DVD диске или возвращается по HTTP запросу), можно в реализации ISequentialStream читать небольшими кусками, если какой-то алгоритм требует продолжения-переключать на другой, когда все потребуют продолжения — переходить на новый кусок.

    DAS>2. Вопрос по реализации. Если я правильно понимаю, между вызовами coroutine

    DAS>ее состояние(локальные переменные и точка возврата) должна где-то
    DAS>сохраняться. Где она сохраняется? Неужели в стеке?

    В С/C++ для Windows можно применять фиберы (CreateFiber, etc). Их контекст такой же как контекст потока: свой стек, занимающий целый мегабайт ВАП, и переключение не очень дешевое.
    Русский военный корабль идёт ко дну!
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.