Да, очень похоже. Там, насколько я понял, используются сопрограммы, которые называются fibers:
What makes this possible is D's support for so called fibers (also often called co-routines). Fibers behave a lot like threads, just that they are are actually all running in the same thread. As soon as a running fiber calls a special yield() function, it returns control to the function that started the fiber. The fiber can then later be resumed at exactly the position and with the same state it had when it called yield(). This way fibers can be multiplexed together, running quasi-parallel and using each threads capacity as much as possible.
зачем намеренно ограничивать используемые типы? я, к примеру, вместо 'std::string' хочу использовать мой 'sometype', который, по сути, со 'std::string' не имеет ничего общего, кроме концепта. сейчас же, при использовании вашего кода, у меня не будет такой возможности. второе — зачем лямбды кастовать в 'std::function<void()>'? какой в этом смысл?
По-моему, очевидно — чтобы не писать шаблоны. Для целей статьи этого более, чем достаточно. Более того, не существует «правильного» варианта написания интерфейса, всегда будут недовольные. Ну и, повторюсь, что для сути статьи это абсолютно безразлично.
думаете, пользователю asio, действительно не нужно знать про io_service, как будто это что-то ненужное? — это ядро asio. первое что должен знать пользователь asio, это именно io_service. более того, открою вам тайну — проактор реализуется именно io_service`ом.
После обертки у нас растворились пользователи asio и появились пользователи Socket, Acceptor, go… И я тоже открою тайну: проактор — это теперь (в статье) реализация, а не интерфейс.
как вы собираетесь обрабатывать исключения, выбрасываемые из io_service::run()?
Как-то так:
typedef std::function<void ()> Handler;
void go(Handler handler)
{
LOG("sync::go");
std::thread([handler] {
try
{
LOG("new thread had been created");
handler();
LOG("thread was ended successfully");
}
catch (std::exception& e)
{
LOG("thread was ended with error: " << e.what());
}
}).detach();
}
Ну, во-первых, хотелось самому пощупать, как оно, реализовать сопрограммы. Во-вторых, хотелось большего контроля над исполнением. В-третьих, хотелось, чтобы читатель примерно понимал, что там под капотом у сопрограмм и как все это дело взаимодействует с асинхронностью. Не вижу причин не использовать в своих проектах уже готовые boost-объекты. Ну и да, для ада и угара.
1. А что не так с Buffer и Handler?
2. Там было еще продолжение: «И откуда пользователю знать, что там должен быть какой-то io_service?». Поясню смысл. boost.asio использует io_service для различных сетевых сущностей. В целом, это дело на совести boost.asio. Но для меня, как пользователя интерфейса, не хочется знать про то, что спрятано под капотом движка. Т.к. мы решаем вполне конкретную задачу, то для нее вполне ожидаемо использовать упрощения. В данном случае, упрощение, связанное с введением синглтона, ни в коей мере не умоляет саму идею про асинхронность.
Рад, что статья понравилась. На самом деле, сопрограммы «переоткрывали» многие, поэтому ничего нового по сути я не написал. Но инертность сознания, конечно, делает свое. Поэтому я попытался явно подчеркнуть преимущество подхода путем сравнения кода. Ну и раскрыть механизмы реализации. Всегда стремился к простоте, и при асинхронности сопрограммы, безусловно, играют яркими красками.
Интересно стало узнать его прохождение и погуляв еще по сети, я так и не нашел, рабочей программной реализации, решения лабиринта.
Спасибо, поржал. Алгоритм для поиска кратчайшего маршрута называется алгоритм Дейкстры. Там же можно найти реализацию. Этот алгоритм отлично ложится на поиск в лабиринте, где выбираются единичные ребра при прохождении. Алгоритм крайне эффективный и находит кратчайший маршрут очень быстро.
Это замечательно, что он интересный. Только меня смущает в нем то, что абсолютно отсутствует мотивация. Взять хотя бы пример с парнем. Что значит, что он не тот единственный? Как она это поняла? Как она поняла то, что ей надо валить из гугла? Каковы причины? Без мотивации это выглядит так, как будто ветер подул и я полетела. Рефлексия должна основываться на логике, а не на эмоциях. При этом я не хочу сказать, что эмоций быть не должно в рефлексии, но они (эмоции) должны четко ложиться в общую картину и выстраиваться в логику. Тогда это можно назвать рефлексией. А тут просто поток сознания.
То же на go: time.Sleep(100 * time.Millisecond)
Что-то на Java я такое не увидел.
Ну и не совсем понятен посыл статьи. Производилось сравнение? Какое сравнение? Читабельности кода? Скорости? Использование тредов вместо гороутин — это совсем не равноценная замена: по семантике они чем-то похожи, а по смыслу — совсем не похожи. Делать выводы на основе одной несложной задачи тоже не совсем верно. Что автор хотел показать-то?
Я может чего-то не понимаю, но по-моему если из статьи удалить весь эмоциональный фон, то получится так: «Я почему-то решила уйти из гугла и ушла. Вроде пока все хорошо».
Для этого вообще-то надо приложить бесконечную силу: сначала была скорость 0, а потом некая константа >0 => ускорение в первый момент времени равно бесконечности. Так что оторваться как раз таки нельзя. А вот отдаляться — пожалуйста.
По разному. Можно — используя атомарные конструкции, можно через мьютексы. Тут стоит обратить внимание не на то, что надо об этом думать, а о том, что автор статьи утверждает, что «доступ к атомарным переменным обходится дорого», поэтому (это уже от меня), дескать, shared_ptr не стоит использовать. Я же говорю, что можно использовать, во-первых, unique_ptr, во-вторых, можно использовать мьютексы, и даже нужно там, где они необходимы.
Автор также говорит про D, типа там есть чистые функции и константные объекты, поэтому есть некие гарантии. Однако, мне не очень понятно, как на D можно работать, на пример, с глобальными контейнерами типа hash_map со всеми ихними константностями и чистыми функциями. Кто-нибудь мне это объяснит? Более того, на С++ тоже можно творить чудеса, см. Полезные идиомы многопоточности С++. В ней я описал, как можно использовать объекты без всяких локов из разных потоках.
Поэтому пафоса автора статья я категорически не разделяю. Указанные примеры кода говорят о том, что автор не знает языка (или знает на достаточно примитивном уровне), и лишь «красиво» треплет языком по делу и без обо всем.
Да, язык С++ не без изъяна, он тяжел для обучения и достаточно громоздок. Но тем не менее, его рано списывать со счетов. Тем более, используя феерические аргументы.
После обертки у нас растворились пользователи asio и появились пользователи Socket, Acceptor, go… И я тоже открою тайну: проактор — это теперь (в статье) реализация, а не интерфейс.
Как-то так:
2. Там было еще продолжение: «И откуда пользователю знать, что там должен быть какой-то io_service?». Поясню смысл. boost.asio использует io_service для различных сетевых сущностей. В целом, это дело на совести boost.asio. Но для меня, как пользователя интерфейса, не хочется знать про то, что спрятано под капотом движка. Т.к. мы решаем вполне конкретную задачу, то для нее вполне ожидаемо использовать упрощения. В данном случае, упрощение, связанное с введением синглтона, ни в коей мере не умоляет саму идею про асинхронность.
Не могли бы вы указать, где тут куча и O(N^4)?
Спасибо, поржал. Алгоритм для поиска кратчайшего маршрута называется алгоритм Дейкстры. Там же можно найти реализацию. Этот алгоритм отлично ложится на поиск в лабиринте, где выбираются единичные ребра при прохождении. Алгоритм крайне эффективный и находит кратчайший маршрут очень быстро.
Что-то на Java я такое не увидел.
Ну и не совсем понятен посыл статьи. Производилось сравнение? Какое сравнение? Читабельности кода? Скорости? Использование тредов вместо гороутин — это совсем не равноценная замена: по семантике они чем-то похожи, а по смыслу — совсем не похожи. Делать выводы на основе одной несложной задачи тоже не совсем верно. Что автор хотел показать-то?
первый — это лок на таблице key-value
второй — на самом Counter
Поэтому никакого дедлока нет. Это называется fine-grained locks. Про это, собственно, и статья (но и не только про это).
Автор также говорит про D, типа там есть чистые функции и константные объекты, поэтому есть некие гарантии. Однако, мне не очень понятно, как на D можно работать, на пример, с глобальными контейнерами типа hash_map со всеми ихними константностями и чистыми функциями. Кто-нибудь мне это объяснит? Более того, на С++ тоже можно творить чудеса, см. Полезные идиомы многопоточности С++. В ней я описал, как можно использовать объекты без всяких локов из разных потоках.
Поэтому пафоса автора статья я категорически не разделяю. Указанные примеры кода говорят о том, что автор не знает языка (или знает на достаточно примитивном уровне), и лишь «красиво» треплет языком по делу и без обо всем.
Да, язык С++ не без изъяна, он тяжел для обучения и достаточно громоздок. Но тем не менее, его рано списывать со счетов. Тем более, используя феерические аргументы.