knkd
Май 14, 2011 14:23:50
Я понял как оно работает, но совершенно не понял зачем.
Чем для многозадачности оно лучше класса с соответствующими методами.
Непонятно…
Андрей Светлов
Май 14, 2011 14:33:36
Потоки операционной системы дорогие. Пару тысяч запустить не получится.
Вместе с тем потоки — естественный способ организации потоков. По крайней мере для большинства программистов более естественный, чем цепочки обратных вызовов.
Вот и делают чтобы было похоже на потоки, а с точки зрения операционной системы было однопоточным приложением.
На Питоне используют гринлеты или генераторы.
doza_and
Май 14, 2011 21:37:01
Я позволю себе добавить.
Оно с одной стороны лучше потоков потому что нет проблем синхронизации, и есть возможность держать полностью под контролем передачу управления между сопроцессами.
С другой стороны лучше классов с методами поскольку контекст выполнения удерживают в стеке (а не в экземпляре класса) поэтому можно устроить рекурсию при вызове сопрограмм.
По стоимости переключение между сопрограммами в винде порядка 100 тактов cpu
Андрей Светлов
Май 14, 2011 22:10:11
Противопоставлять потоки (любые) классам я бы не стал. Это как спрашивать: лимон желтый или кислый?
Проблема синхронизации — слишком общее понятие.
Сопрограммы используют объекты синхронизации. Называют их каждый раз по новому — семафоры, каналы, очереди. Только мьютексов нет.
А Deadlocks, кстати, очень даже могут быть.
doza_and
Май 14, 2011 22:32:22
Может мы несколько о разном говорим.
Я имел ввиду легковесные потоки, или то что в виндах fiber называется. По сути это просто дополнительная структура управления в языке - переход с одного стека на другой и переход на другой поток управляющих команд. В этом случае никаких семафоров и прочего просто нет - эти потоки не выполняются одновременно, переключения между потоками инициируется самими потоками - синхронно. Зациклить программу кончено можно, но это как for(;; ){} написать. Аналогичный механизм - обработчики прерываний, отличие только в асинхронности момента переключения, поэтому тут уже важно не нарушить структуру данных. Сложнее немного но проблем синхронизации(в смысле использования семафоров локов и мьютексов) все равно нет.
p.s.
Я довольно давно на фиберах сделал себе yield для с++. Никаких проблем синхронизации пока не заметил.
Андрей Светлов
Май 14, 2011 22:46:10
Ааа. Да, действительно говорим о чуть-чуть разном.
Добавьте к вашим потокам I/O. И чтобы вместо блокировки на этом вводе-выводе было переключение на следующий свободный поток. И переключение обратно как только операция будет готова и можно идти дальше. А явное переключение — лишь дополнительная приятная особенность. Типа Sleep(0) на Win32 или pthread_yield() на linux. Мультизадачность невытесняющая, но блокировка на вводе-выводе переключает контекст. Совсем как на древних операционных системах.
Переключение ведь обычно делают «на следующий», не указывая конкретный поток-приемник. Чтобы от интеллектуальных усилий умом не тронуться.
Вот тут сразу же появляется синхронизация потоков. Переключения детерминистические в том смысле, что они происходят в известных местах кода. Но в более или менее нетривиальной программе предсказать моменты этих переходов, построить автомат состояний — невозможно. Такой уж этот непредсказуемый ввод-вывод. Так и получается, что нужно строить каналы и семафоры, чтобы микропотоки могли совместно работать.
knkd
Май 15, 2011 00:21:29
doza_and
онтекст выполнения удерживают в стеке (а не в классе) поэтому можно устроить рекурсию при вызове сопрограмм.
Ага!