powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничная со-программа
54 сообщений из 54, показаны все 3 страниц
Тяпничная со-программа
    #39294661
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день коллеги. С пятницей.

Я долго думал куда поместить этот сабж. В С++, Java или программинг. И решил все таки здесь т.к.
тема достаточно общая и о ней стоит говорить сразу в контексте многих языков.

Тема - со-программами или co-routines

Я квотирую определение с вики чтоб было понятно

wikiСопрограмма (англ. coroutine) — компонент программы, обобщающий понятие подпрограммы,
который дополнительно поддерживает множество входных точек (а не одну как подпрограмма),
остановку и продолжение выполнения с сохранением определённого положения.

Сопрограммы являются более гибкими и обобщёнными, чем подпрограммы, но реже используются
на практике. Применение сопрограмм являлось методикой ещё ассемблера, практиковалось
лишь в некоторых высокоуровневых языках (Simula, Modula-2). Сопрограммы хорошо
пригодны для реализации многих похожих компонентов программ (итераторов, бесконечных
списков, каналов, совместных задач).


Под катом - мотивация сабжа для меня.

Год назад я пытался нарисовать картинку Тяпничная география
- распределение Ipv4 адресов по странам и отображение этого
на диаграмме в виде цветных квадратов.

Это была не бизнес разработка и чуть позже она мне надоела и я ее отложил.

Для рисования квадратов я кодил заполняющую кривую Гилберта. И резальтатом разработок
была экспериментальная консольная тулза https://sourceforge.net/p/countryipdiagram/code/HEAD/tree/trunk/utils/src/gilbertroute.c
которая должна быть генератором координат Гилберта. Сами коды выводились в stdout для передачи в другую утилиту.

Но работать с pipeline-ом процессов неудобно. Мне нужна была генерализация алгоритма в виде шаблона алгорима
чтоб я мог его подставлять в любой код.

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

Второй вариант - использовать механизмы очередей (на базе BlockingQueue в Java к примеру) для того чтобы иммитировать поведение
итератора с рекурсией. Способ оригинальный. Но есть недостаток. Мы вводим еще один вычислительный поток в задачу которая по сути
является однопоточной. Отсюда автоматом - структуры данных которым нужна синхронизация (BlockingQueue) и накладные.

Вобщем нужен гладкий и удобный механизм разворачивания рекурсивных функций в генераторы.

Вобщем как обстоят дела с со-программами (co-routines) в С/С++/C#/Java/Groovy/Scala/JavaScript/Delphi.


Прошу прощения если я не упомянул ваш любимый язык X. Я просто не успел просмотреть обзоры фичей всех ваших языков.


Я вот сделал некоторую табличку в которой попробовал обрисовать положение вещей на текущий момент

Поддержка со-программ в ЯП
LanguageCo-routines supportCno supportС++Возможно с поддержкой boost::coroutinesC#with yield returnJavano suportGroovy?Scalawith yieldDelphino supportJava Script Since ECMA6
В многочисленных статьях также упоминается что для поддежки co-routines язык
или среда должен поддерживать continuations.

Вот такая ситуация. У кого какие были практики с coroutines? Поделитесь.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294711
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Было бы круто, если бы был полностью рабочий локализованный пример, который использует сопрограммы или который не использует, но при их наличии был бы намного понятнее/быстрее, на любом из упомянутых языков на онлайн компиляторе: http://ideone.com/

Так было бы намного наглядней. Пока что ни разу не встречал такого примера. Либо примеры все усложняют, либо упрощают, но используют какие-то гипотетические сторонние функции, которые почему-то не могут сохранить свое текущее состояние: ни в передаваемую структуру, ни в объект членом которого они являются, ни в стороннюю структуру куда можно обратиться по хэндлеру.

Нафига выходить по yield, выходи по return, а текущее состояние всех итераторов храни как члены класса, сохранятся в объекте.
Если просто хочется распараллеливания, то используй потоки, выходи по yield(), и используй потокобезопасный обмен - ровно теже сопрограммы.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294718
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonУ кого какие были практики с coroutines? Поделитесь.
Используем в продакшене Boost.Coroutine (для асинхронных операций).
Код на порядок проще и понятнее, чем с колбэками.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294720
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,
а goto отменили что ли уже?

как то давно, когда студентом был, делал нитевую многопоточность на TurboPascal-е, в общем-то такую вещь там можно было реализовать.

каналы как абстракция делаются в любом из языков поддерживающих генерики или метапрограммирование, зачем для этого делать языковые конструкции?
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294721
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася УткинНафига выходить по yield, выходи по return, а текущее состояние всех итераторов храни как члены класса, сохранятся в объекте.
Так написал же человек - не хочет он явно хранить состояние, когда алгоритмически никакого состояния нет.
Т.е. то что вы предлагаете, это усложнение алгоритма.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294722
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я щас сходу не готов дать охватывающий пример. У меня щас нет такого под рукой.

Но я могу привести контр-пример. Возьмите любую древовидную структуру данных. Или графовую.
И сделайте по ней алгоритм итератора.

Обеспечте интерфейс который обходит все узлы:

Код: plaintext
1.
2.
3.
4.
interface RecursiveIterator<Node>{
  bool hasNext();
  Node next();
}



Это и есть контр пример. Тоесть пример того как кодить неудобно.

Без использования уступчивого return, мультипоточности и contnuations.

Это моё ИМХО.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294726
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)mayton,
а goto отменили что ли уже?

как то давно, когда студентом был, делал нитевую многопоточность на TurboPascal-е, в общем-то такую вещь там можно было реализовать.

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

Приведите пример плиз. Буду признателен.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294736
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonНу... я готов покорректировать табличку. Наверное в Турбо-Паскале есть языковый API для работы
с каналами. Я этого не знал.
языковых конструкций нету, я же говорю делал нитевидную многозадачность под досом
выделялась память под стэк и проца yield, которая меняла регистр SP на доступные стэки.
Сомневаюсь что так можно под виндой сделать, хотя попробовать не мешает ...

а каналы генериками в Delphi, fpc делаются довольно легко
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294737
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)а каналы генериками в Delphi, fpc делаются довольно легко
Но это language features? Или нет?
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294741
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonЯ щас сходу не готов дать охватывающий пример. У меня щас нет такого под рукой.

Но я могу привести контр-пример. Возьмите любую древовидную структуру данных. Или графовую.
И сделайте по ней алгоритм итератора.

Обеспечте интерфейс который обходит все узлы:

Код: plaintext
1.
2.
3.
4.
interface RecursiveIterator<Node>{
  bool hasNext();
  Node next();
}



Это и есть контр пример. Тоесть пример того как кодить неудобно.

Без использования уступчивого return, мультипоточности и contnuations.

Это моё ИМХО.
а в чем проблема указатели в стэке сохранить?

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
   generic BinMapEnum<TBinNode,TItem>=class(TObject)
    public
     type
       PBinNode=^TBinNode;
    private
     Stack:TStack;
     CurrentNode:PBinNode;
     function GetCurrent: TItem;
    public
     constructor Create(const ARoot:PBinNode);
     destructor Destroy;override;

     function MoveNext: Boolean;
     property Current: TItem read GetCurrent;
   end;

{ BinMapEnum }

function BinMapEnum.GetCurrent: TItem;
begin
  Result:=CurrentNode^.Data;
end;

constructor BinMapEnum.Create(const ARoot: PBinNode);
var N:PBinNode;
begin
  inherited Create;
  N:=ARoot;
  while N<>nil do begin
    Stack.Push(N);
    N:=N^.Left;
  end;
end;

destructor BinMapEnum.Destroy;
begin
  Stack.Done;
  inherited Destroy;
end;

function BinMapEnum.MoveNext: Boolean;
begin
  if CurrentNode=nil then begin
    CurrentNode:=Stack.Pop;
  end else begin
    if CurrentNode^.Right<>nil then begin
      CurrentNode:=CurrentNode^.Right;
      While CurrentNode^.Left<>nil do begin
        Stack.Push(CurrentNode);
        CurrentNode:=CurrentNode^.Left;
      end;
    end else begin
      CurrentNode:=Stack.Pop;
    end;
  end;

  Result:=(CurrentNode<>nil);
end;


...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294743
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonkealon(Ruslan)а каналы генериками в Delphi, fpc делаются довольно легко
Но это language features? Или нет?
это скорее language-oldest, зачем это делать если либами можно сделать? да и с ОС проблемы, она просто так стэковые регистры менять не даёт
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294746
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
   generic BinMapEnum<TBinNode,TItem>=class(TObject)
    public
     type
       PBinNode=^TBinNode;
    private
     Stack:TStack;
     CurrentNode:PBinNode;
     function GetCurrent: TItem;
    public
     constructor Create(const ARoot:PBinNode);
     destructor Destroy;override;

     function MoveNext: Boolean;
     property Current: TItem read GetCurrent;
   end;



Эээ... надо подумать.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294780
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
yield в C# это тема, правда я в нее еще не вникал глубоко. Тут фундаментально меняется подход, ты получаешь на вход интерфейс, который будет (будет в будущем) возвращать тебе последовательность, дальше можно его передать на вход следующей функции и т.д. Это и есть основа LINQ.
И в итоге это выглядит так, например найти первое число в массиве между 1-10
Код: c#
1.
res = array.Where(x => x >= 1 && x <= 10).Single();


и тут перебор будет именно до первого удовлетворяющего условию. Синтаксический сахар конечно, но сахар он на то и нужен чтобы сладко было.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294785
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, это пример вырожденный. Его легко итерациями сделать.
А вот задачка обхода деревьев как функция которая возвращает
узлы - это красиво.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294786
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonDima T, это пример вырожденный. Его легко итерациями сделать.
Я не спорю, я же написал что это синтаксический сахар, но я не люблю С/С++ именно за то что обязательно надо это делать, т.е. писать кучу букав, потом отлаживать, а тут написал одну строчку и получил что хотел. Мне не нравится С именно поэтому, т.к. для элементарного действия надо написать портянку на два экрана, когда в высокоуровневом ЯП это одна строка.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294790
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дима.

1) Я понял. Я думаю что ближайшие лет 10 основной темой споров будут
доводы за и против лямбд и Stram-операций в обычных ЯП.

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

Но эта тема другого топика.

2) Я вернусь к своим баранам. А именно к coroutine. Разворачивая рекурсию
в С-программе которую я привел выше я пришел к следующему итератору.

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

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
public class GilbertIteratorBlockingQueue implements Iterator<Position> {

    static Logger logger = LogManager.getLogger(GilbertIteratorBlockingQueue.class);

    Producer producer;
    int size;
    BlockingQueue<Position> queue;
    Position position = Position.DUMMY;
    int state = 0;

    public GilbertIteratorBlockingQueue(int size) {
        if (size<4){
            throw new IllegalArgumentException("The dimension of 'Gilbert' curve cannot be less than 4 x 4!");
        }
        this.size = size;
        queue = new ArrayBlockingQueue<>(1024);
        producer = new Producer();
        new Thread(producer).start();
    }


    class Producer implements Runnable {

        static final int u = 1;
        int glx;
        int gly;
        int level;

        public Producer() {
            level = log2up(size);
            int clp2size = clp2(size);
            if (clp2size > size) {
                logger.warn("Warning! The real dimension of iterator's space has been extended to {}x{} pixels", clp2size, clp2size);
            }
            state = 1;
        }

        public void run() {
            try {
                moveto(0, 0);
                a(level);
                queue.put(Position.DUMMY);
            } catch (InterruptedException e) {
                logger.error(e);
            }
        }

        void linerel(int x, int y) throws InterruptedException {
            glx += x;
            gly += y;
            queue.put(new Position(glx, gly));
        }

        void moveto(int x, int y) throws InterruptedException {
            glx = x;
            gly = y;
            queue.put(new Position(glx, gly));
        }

        // Elements of curve
        void a(int i) throws InterruptedException {
            if (i > 0) {
                d(i - 1);
                linerel(+u, 0);
                a(i - 1);
                linerel(0, u);
                a(i - 1);
                linerel(-u, 0);
                c(i - 1);
            }
        }

        void b(int i) throws InterruptedException {
            if (i > 0) {
                c(i - 1);
                linerel(-u, 0);
                b(i - 1);
                linerel(0, -u);
                b(i - 1);
                linerel(u, 0);
                d(i - 1);
            }
        }

        void c(int i) throws InterruptedException {
            if (i > 0) {
                b(i - 1);
                linerel(0, -u);
                c(i - 1);
                linerel(-u, 0);
                c(i - 1);
                linerel(0, u);
                a(i - 1);
            }
        }

        void d(int i) throws InterruptedException {
            if (i > 0) {
                a(i - 1);
                linerel(0, u);
                d(i - 1);
                linerel(u, 0);
                d(i - 1);
                linerel(0, -u);
                b(i - 1);
            }
        }


    }

    @Override
    public boolean hasNext() {
        if (state == 2){
            return false;
        }
        try {
            position = queue.take();
            if (position == Position.DUMMY) {
                state = 2;
                return false;
            }
        } catch (InterruptedException e) {
            logger.error(e);
        }
        return true;
    }

    @Override
    public Position next() {
        return position;
    }
}



Меня это обескураживает и я ищу простые лаконичные механизмы
не жрущие списки памяти и в то-же время выдающие сиквенс
значений из рекурсии.

Напомню о проблеме. Мне надо было заполнить пикселами картинку
в порядке кривой Гилберта. Но я не хотел хардкорное решение.
Мне нужны были компоненты которые "чертят" спирали, Z-кривые, змейки
и кривые Гилберта и Пеано. И пока у меня не было такой компоненты
сам кодинг плаката с IP-диаграммой мне был не интересен. И мне нужен
был механизм переключений между этими "чертилками".



3) По поводу Streams (Java8). Я надеюсь они мне позволят заменить со-программы.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294809
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonМеня это обескураживает и я ищу простые лаконичные механизмы
не жрущие списки памяти и в то-же время выдающие сиквенс
значений из рекурсии.

рекурсия это и есть список памяти, ты просто фактически не хочешь о нём заботиться сам
Рекурсия кстати процентов на 20-30 медленнее (за счёт сохранения всех данных). Чем стэковый автомат в уже выделенном блоке. За простоту кода приходится платить ресурсами.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294813
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)рекурсия это и есть список памяти, ты просто фактически не хочешь о нём заботиться сам
Рекурсия кстати процентов на 20-30 медленнее (за счёт сохранения всех данных). Чем стэковый автомат в уже выделенном блоке. За простоту кода приходится платить ресурсами.
Очень часто мы (разработчики) согласны платить 20-30% (здесь я сомневаюсь надо пересчитать)
но при этом иметь простой концептуальный код.

Если yield return несет в себе нулевые накладные расходы (синхронизации нет, нет потоков, IPC,
и очередей) то я согласен и я хочу использовать этот return в противоположность разворачиванию
рекусии в конечный автомат.

Заметьте что мы с вами еще не рассматривали оценку сложности этого процесса.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294814
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я имею в виду оценку сложности процесса переписывания рекурсии в автомат со стеком.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294823
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonЕсли yield return несет в себе нулевые накладные расходы (синхронизации нет, нет потоков, IPC,
и очередей) то я согласен и я хочу использовать этот return в противоположность разворачиванию
рекусии в конечный автомат.

несёт, для них нужен отдельный блок стэка, сколько его выделить 100кб, 1Мб или больше?
траты на yield в общем случае : все регистры, связка pushad-popad довольно быстрая, но не бесплатная операция. это мы ещё не вспоминаем про регистры fpu

maytonЗаметтье что мы с вами еще не рассматривали оценку сложности этого процесса.


есть ещё вариант: если в функциональном стиле написать алгоритм, то его можно довольно просто механически разложить через комбинаторы в "автомат со стэковой памятью"
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294944
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

вот же нашёл ты тему, всё таки получилось у меня это сделать
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294952
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan), спасибо. Но я не специалист в FreePascal. Вряд-ли я могу собрать это.

А вот по поводу комбинаторов и автоматов со стеком - подкинь материала.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39294955
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonkealon(Ruslan), спасибо. Но я не специалист в FreePascal. Вряд-ли я могу собрать это.

А вот по поводу комбинаторов и автоматов со стеком - подкинь материала.
тут надо подумать, знаю что можно, но вот где и когда читал - подзабыл
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295061
Фотография tchingiz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторподдерживает множество входных точек (а не одну как подпрограмма),
остановку и продолжение выполнения с сохранением определённого положения.
...
Применение сопрограмм .....практиковалось
лишь в некоторых высокоуровневых языках (Simula, Modula-2)
по моему брехня.
точки входа в подпрограмму были чуть ли не везде (пл-1 и алгол), а продолжать выполнение с сохранением определенного положения -- можно благодаря static
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295092
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tchingizточки входа в подпрограмму были чуть ли не везде (пл-1 и алгол), а продолжать выполнение с сохранением определенного положения -- можно благодаря static

Fullstack CoRoutines на основе одной переменной в общем виде повторить не получится
смотри пример с обходом бинарного дерева

рекурсию всё равно с помощью стэка придётся делать в том или ином виде
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295099
Фотография tchingiz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а с двумя переменными?
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295118
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tchingizа с двумя переменными?
с конечным числом переменных в общем виде - никак
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295170
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Видел поддержку сопрограмм в спецификации на С-- (которая в виде pdf).

Я так понял, что вся эта чехарда была только для того, чтобы Глазго Хаскель компилятор мог эффективно реализовать ФП.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295171
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну и вроде бы потом GHC перешел на LLVM, значит и там подобное есть.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295178
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Siemargl,

не, хаскелю вообще по барабану, в LLVM для них уже добавили какую-то свою модель вызова им и так хватает

http://www.gamedev.ru/flame/forum/?id=184103
Скорее всего для того, что-бы вручную не писать конечные автоматы, ибо низкоуровневая конструкция
или возможно за go гонятся, для эффективной реализации.
геморно как-то на ассемблере переключатель писать, почти под каждую систему свой
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295185
Владимир2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Экспромтом.

Если бы C++ поддерживал goto c динамической меткой, то со-программа с множественным входами могла бы выглядеть так:

DemoFunc( params ..., Метка ) {

goto Метка;

Start1:
...
...
Start2:
...
...
StartXX:
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295217
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Владимир2012Экспромтом.

Если бы C++ поддерживал goto c динамической меткой, то со-программа с множественным входами могла бы выглядеть так:

DemoFunc( params ..., Метка ) {

goto Метка;

Start1:
...
...
Start2:
...
...
StartXX:о боже
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
enum Mark { Start1, Start2, StartXX };
void DemoFunc( params ..., Mark startmark )
{
   switch( startmark ) {
       case Start1:
          ...
          ...
      case Start2:
          ...
          ...
      case StartXX:
          ...
          ...
      default:
          throw std::exception( "Unknown start mark" );
   }
}
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295221
Владимир2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egorychо боже
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
enum Mark { Start1, Start2, StartXX };
void DemoFunc( params ..., Mark startmark )
{
   switch( startmark ) {
       case Start1:
          ...
          ...
      case Start2:
          ...
          ...
      case StartXX:
          ...
          ...
      default:
          throw std::exception( "Unknown start mark" );
   }
}

Ужас!
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295233
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Владимир2012Ужас!ты ведь сам этого хотел, товарищ ))
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295241
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пора реализовывать рекурсивный итератор. Пробую на Scala... под катом - эксперименты.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
  /**
    * mayton >> В топку Груви. Решил взять Scala. Экспериментирую. Пока не могу понять что нужно
    * Iterable? Collection? Stream? Списки в стили Lisp вида 1 :: 2 :: nil ...
    *
    * Даллее идет проба пера...
    */
  def getPosition(size:Int) : Position = {
    new Position(0,0)
  }

  /**
    * mayton >> Это гребаный список. Но мне нужен ленивый мать его список через yield...
    */
  def getPositionList(size:Int) : List[Position] = {
    List(new Position(0,0))
  }

  /**
    * mayton >> Итератор...
    */
  def getPositionIterator(size:Int) : Iterable[Position] = {
    List(new Position(0,0)).toIterable
  }

  /**
    * Это украдено у Хорсмана 'Scala'.... типа конструирование бесконечных списков
    * в стиле Лиспа. Здесь насколько я понял определена бесконечноая последовательность
    * целых начиная с n
    */
  def numsFrom(n:Int) : Stream[Int] = {
    n #:: numsFrom(n+1)
  }

  /**
    * Но у меня рекурретная формула. Мне больше подходит шаблон yield return
    * Как совокуплять эти хеши с двоеточиями в алгоритме - ХЗ ненадежно
    *
    * пробуем...
    *
    * Здесь Scala plugin ругнулся и предложил сделать варианты:
    * 1) add 'Collection BreakOut' argument
    * 2) change Stream[Int] to
    *
    * ну ладно пробуем...
    */
  //def numsFrom2(n:Int) : Stream[Int] = {
    //for(i <- n to Int.MaxValue) yield n
  //}

  def numsFrom2(n:Int) : Stream[Int] = {
    (for(i <- n to Int.MaxValue) yield n)(collection.breakOut)
  }

  def numsFrom3(n:Int) : IndexedSeq[Int] = {
    for(i <- n to Int.MaxValue) yield n
  }

  // Хм... странно следкющий пример не компилится
  // [ERROR] Illegal star of statement yield 1
  //                                   ^
  def numsFrom4(n:Int) : IndexedSeq[Int] = {
    yield 1
    yield 2
  }

...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295311
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295324
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КМК это не совсем то что я хотел.

Код: java
1.
2.
3.
4.
5.
6.
7.
getStatesOfChildNodes(node, path, deep) {
        return node.children
            .map((child, key) =>
                this.getState(node, child, key, path.concat(child.cost), deep + 1))
            .sort((a, b) =>
                a.node.cost - b.node.cost);
    }



Настораживает наличие вызова .sort(). Если это генерация списка с сортировкой то я это и так могу сделать в С++/Java
но весь цимес в том что я не хочу нигде хранить никаких списков. Мне нужен генератор который выдает
самый первый элемент настолько быстро, насколько это возможно.

Без промежуточных переливаний в массивы или списки. Мне нужен Stream.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39295432
Владимир2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egorychты ведь сам этого хотел, товарищ )) ...
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296334
Фотография fixxer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Зачем тебе для этой задачи сопрограммы, если достаточно ленивых списков?

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
val p = 5
val u = 10

def a(i: Int): Stream[(Int, Int)] =
  if (i > 0)
    d(i - 1) #::: (u, 0) #:: a(i - 1) #::: (0, u) #:: a(i - 1) #::: (-u, 0) #:: c(i - 1)
  else Stream.empty

// аналогично определяем b, c, d

a(p).scanLeft((startX, startY))((a, b) => (a._1 + b._1, a._2 + b._2)).take(numPoints).foreach(...
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296476
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fixxer,

жесть, а в какой последовательности всё это вычисляется? точно "лениво"?


проще CreateFiber и SwitchToFiber использовать
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296553
Фотография fixxer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)fixxer,
жесть, а в какой последовательности всё это вычисляется? точно "лениво"?


В той последовательности как написано, да, точно лениво. #::: оператор конкатенации ленивых списков, #:: оператор присоединения головы к списку. Оба оператора правоассоциативны. То есть читать так:

Код: sql
1.
d(i - 1) #::: ( (u, 0) #:: ( a(i - 1) #::: ( (0, u) #:: ( a(i - 1) #::: ( (-u, 0) #:: c(i - 1) ) ) ) ) )



Правая часть не вычислится пока не попросишь.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296573
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fixxer, ну ... я-бы не стал противопоставлять один термин другому.

Если вы хотите называть это ленивым списком - я не против.

Я просто начал свои копания с уступчивого return и пришел к постановке вопроса.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296579
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)fixxer,

жесть, а в какой последовательности всё это вычисляется? точно "лениво"?


проще CreateFiber и SwitchToFiber использовать
Я-бы не хотел не акцентировать внимание на Windows API.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296582
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonЯ-бы не хотел не акцентировать внимание на Windows API.
ну тогда для С++ только буст, собственно он под виндой, наверное, и использует fiber-ы
на асемблере писать под все архитектуры и ОС тоже не очень
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296585
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)maytonЯ-бы не хотел не акцентировать внимание на Windows API.
ну тогда для С++ только буст, собственно он под виндой, наверное, и использует fiber-ы
на асемблере писать под все архитектуры и ОС тоже не очень
Было-бы неплохо чтобы господин СтраусТруп подумал в этом направлении.
Если такое реализовать невозможно в рамках language (вовлечение сущностей
уровня kernel API в язык) то хотелось-бы видеть Note #... где такой
вопрос хотя-бы рассматривался.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296586
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fixxerПравая часть не вычислится пока не попросишь.
Спасибо. Я попробую ваш пример сегодня. Может это и будет мое решение.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296593
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,
ну собственно как-то как показал fixxer и разлагается любая рекурсия

1. нанизывается последовательность действий https://habrahabr.ru/post/153383/
2. в компиляторе разлагается на комбинаторы, тут прямых линков дать не могу
собственно в данном случае используются комбинатор пары \x.y.f = f x y и Y-комбинатор (комбинатор неподвижной точки)

http://ru.wikibooks.nym.su/wiki/Комбинаторы_—_это_просто!
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296605
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonБыло-бы неплохо чтобы господин СтраусТруп подумал в этом направлении.
Если такое реализовать невозможно в рамках language (вовлечение сущностей
уровня kernel API в язык) то хотелось-бы видеть Note #... где такой
вопрос хотя-бы рассматривался.
Ну почему, с определёнными ограничениями можно, я же написал без прямой поддержки ОС (в Win64 только с исключениями глючит, но это просто я плохо знаю Win64 на уровне асма и материалов толковых нет как по Win32). Мне fiber не нравится тем, что он сам память выделяет и swich у него замудрёный - MS, как всегда, простую вещь сделала через одно место.

PS: try-finally-except тоже в каждой ОС по разному реализуется, ничего - сделали же
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296666
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonkealon(Ruslan)пропущено...

ну тогда для С++ только буст, собственно он под виндой, наверное, и использует fiber-ы
на асемблере писать под все архитектуры и ОС тоже не очень
Было-бы неплохо чтобы господин СтраусТруп подумал в этом направлении.
Если такое реализовать невозможно в рамках language (вовлечение сущностей
уровня kernel API в язык) то хотелось-бы видеть Note #... где такой
вопрос хотя-бы рассматривался.
Да полно:

v1 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3650.pdf
v1+ https://isocpp.org/files/papers/N3722.pdf
v2 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4134.pdf
v4 https://isocpp.org/files/papers/N4402.pdf

Эксперементальная реализация в MSVS 2015 - кстати, с короткими понятными примерами: https://blogs.msdn.microsoft.com/vcblog/2014/11/12/resumable-functions-in-c/
#include <experimental/resumable>
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296669
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася Уткин, спасибо.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39296673
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С примером fixxer сегодня не успвеваю. Но вот пока есть порт с С на Scala.
Здесь yield return был-бы удобен тем что ничего кардинально переписывать не нужно.
Почти любой алгоритм существует в классическом императивном (а не списковом) виде
и мне как человеку достаточно ленивому можно было-бы в идеале сделать косметический
реплейсмент.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
package mayton.image

object ScalaMain {

  val u = 1

  var glx: Int = 0
  var gly: Int = 0

  def linerel(x: Int, y: Int) {
    glx += x
    gly += y
    printf("%d,%d\n", glx, gly)
  }

  def moveto(x: Int, y: Int) {
    glx = x
    gly = y
    printf("%d,%d\n", glx, gly)
  }

  def a(i: Int) {
    if (i > 0) {
      d(i - 1)
      linerel(+u, 0)
      a(i - 1)
      linerel(0, u)
      a(i - 1)
      linerel(-u, 0)
      c(i - 1)
    }
  }

  def b(i: Int) {
    if (i > 0) {
      c(i - 1)
      linerel(-u, 0)
      b(i - 1)
      linerel(0, -u)
      b(i - 1)
      linerel(u, 0)
      d(i - 1)
    }
  }

  def c(i: Int) {
    if (i > 0) {
      b(i - 1)
      linerel(0, -u)
      c(i - 1)
      linerel(-u, 0)
      c(i - 1)
      linerel(0, u)
      a(i - 1)
    }
  }

  def d(i: Int) {
    if (i > 0) {
      a(i - 1)
      linerel(0, u)
      d(i - 1)
      linerel(u, 0)
      d(i - 1)
      linerel(0, -u)
      b(i - 1)
    }
  }

  def flp2(arg1: Int): Int = {
    var x = arg1
    x = x | (x >> 1)
    x = x | (x >> 2)
    x = x | (x >> 4)
    x = x | (x >> 8)
    x = x | (x >> 16)
    x - (x >> 1)
  }

  def clp2(arg1: Int): Int = {
    var x = arg1
    x = x - 1
    x = x | (x >> 1)
    x = x | (x >> 2)
    x = x | (x >> 4)
    x = x | (x >> 8)
    x = x | (x >> 16)
    x + 1
  }

  def nlz(arg1: Int): Int = {
    var n: Int = 0
    var x = arg1
    if (x == 0){
      return 32
    }
    n = 1
    if ((x >> 16) == 0) {
      n += 16
      x <<= 16
    }
    if ((x >> 24) == 0) {
      n += 8
      x <<= 8
    }
    if ((x >> 28) == 0) {
      n += 4
      x <<= 4
    }
    if ((x >> 30) == 0) {
      n += 2
      x <<= 2
    }
    n = n - (x >> 31)
    n
  }

  def log2up(x: Int): Int = {
    if (x < 1)
      0
    else
      32 - nlz(x - 1)
  }

  def main(args: Array[String]): Unit = {


    if (args.length == 0) {

      printf("\nGilbert Route 1.0 (c) Mayton and SQL.RU. Written in 'Scala' :)\n")
      printf("\nUsage: gilbertroute [ { level=N | size=M } [binaryout]] [help]\n")
      printf("\nWhere:\n")
      printf("\n       M          : { 32 | 64 | 128 | 256 ... etc powers of two} ")
      printf("\n       N          : { 1,2,3...}")
      printf("\n")
      System.exit(-1)

    } else {

      var level:Int = -1
      var size:Int = -1
      val arg1 = args(0)

      if (arg1.substring(0,5) == "size="){
        val size:Int = arg1.substring(5).toInt
        if (size<=0){
          printf("\nGilbertroute: Error! Argument size cannot be zero or negative.\n")
          System.exit( -3 )
        }
        level = MathUtils.log2up(size)
      } else if (arg1.substring(0,6)=="level="){
        level = arg1.substring(6).toInt
        if (level<0){
          printf("\nGilbertroute: Error! Argument level cannot be negative.\n")
          System.exit( -3 )
        }
      }

      if (level>=0){
        moveto(0, 0)
        a(level)
        System.exit( 0 )
      } else {
        printf("\nGilbertroute: Error! Unrecognized argument.\n")
        System.exit( -2 )
      }
    }

  }
}

...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39298977
Serg_77m
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonПоддержка со-программ в ЯП
LanguageCo-routines supportCno support
Для C есть Portable Coroutine Library (PCL)
А ещё в C возможен такой трюк (для меня это было открытием).

kealon(Ruslan)языковых конструкций нету, я же говорю делал нитевидную многозадачность под досом выделялась память под стэк и проца yield, которая меняла регистр SP на доступные стэки.
Сомневаюсь что так можно под виндой сделать, хотя попробовать не мешает ...Только что проверил под Linux (gcc x86). Внутри функции ассемблерной вставкой можно запросто поменять значение esp, поставив его на буфер, выделенный malloc'ом. Причём, функция после этого продолжает видеть свои параметры, и нормально завершается по return. Теперь добавить куда-нибудь в начало longjmp, в точках yield return вставить setjmp, и задача почти решена... кажется, так оно и сделано в PCL. Только там ассемблерных вставок нет, но есть хакерские манипуляции с jmp_buf.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39299021
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Serg_77m, это мегакруто. PCL.

Но КМК это левел библиотеки а не языка.
...
Рейтинг: 0 / 0
Тяпничная со-программа
    #39299077
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Serg_77mТолько что проверил под Linux (gcc x86). Внутри функции ассемблерной вставкой можно запросто поменять значение esp, поставив его на буфер, выделенный malloc'ом. Причём, функция после этого продолжает видеть свои параметры, и нормально завершается по return. Теперь добавить куда-нибудь в начало longjmp, в точках yield return вставить setjmp, и задача почти решена... кажется, так оно и сделано в PCL. Только там ассемблерных вставок нет, но есть хакерские манипуляции с jmp_buf.
Оптимизацию включи.

Оптимизм то и выключится
...
Рейтинг: 0 / 0
54 сообщений из 54, показаны все 3 страниц
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничная со-программа
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]