
Oleg
20.10.2017
10:34:54
Ну или хотя ldc должен быть версии с raii

Dmitry
21.10.2017
07:32:51
Блин, мой любимый вопрос. По файберам
foo()
{
блокирующаяОперация()
yield()
}
Как будет происходить переключение на другой файбер, если у нас ялд будет вызван только после выполнения блокирующей операции
Во, очень интересную штуку нашел. Как я понимаю весь рантайм NET уместили в 40 тыс строк кода
https://www.codeproject.com/Articles/1211457/DotNetAnywhere-An-Alternative-NET-Runtime

Dmitry
21.10.2017
08:12:50
> рантайм NET уместили в 40 тыс строк кода
Интересно было бы с жабой сравнить. Вернее, с жабами, они же разные есть.

Google

Friedrich
21.10.2017
08:17:22
35k строк gc.cpp и ещё 5k строк нормального кода ?
(нет)

Ievgenii
21.10.2017
08:29:21

Dmitry
21.10.2017
08:29:44
А как в нормальном коде делается чтобы блокировки не было?

Ievgenii
21.10.2017
08:35:56
А какого типа блокировка?
Что это за операция?

Andrey
21.10.2017
09:07:23
либо проверяем состояния дескриптора чере select к примеру. если должен заплокироваться при чтении - йыэлд

Dmitry
21.10.2017
09:34:27
@asan13 у меня картинка в голове не формируется упорно. Неблокирующий метод в себе же должен содердать какую-то логику?

Ievgenii
21.10.2017
09:36:00
Вон тебе выше сказали решение, при блокирующих операциях типа работы с сетью
смотри
если блокируящая операция - это чего-то расчет, типа матиматика, то тут сложно.
Если это простое IO, то нужно с ней просто в не блокирующем режиме работать

Google

Ievgenii
21.10.2017
09:37:16
и все

Dmitry
21.10.2017
09:38:41
тоесть функция чтения (потенциально блокирующая) должна в себе содержать какую-то логику? Навроде:
1. проверить есть ли данные в буфере
2. если их нет сделать yield
3. если есть считать

Ievgenii
21.10.2017
09:39:07
Что-то вроде того
Тогда у тебя эта операция будет не блокирующей

Dmitry
21.10.2017
09:40:17
А вот операция ссчитывания они же тоже в каком-то потоке должна выполяться? Есть какие-то системные потоки? Просто данные же должен кто-то ссчитывать

Ievgenii
21.10.2017
09:40:53
не понял

Dmitry
21.10.2017
09:41:30
ну вот операция ссчитывания она же должна кем-то выполняться

Ievgenii
21.10.2017
09:41:53
Считывания откуда?
Из stdIn?

Dmitry
21.10.2017
09:42:07
пусть будет из файла

Ievgenii
21.10.2017
09:42:37
Смотри
Берем файл
Открываем его на чтение
И читаем его только тогда, когда появляется время на его чтение
Если сокет - то читаем только тогда, когда что-то приходит в него (меняется его внутренее состояние)
Читаем не весь файл
А читаем только ту часть, которая не будет ущербна для работы всего приложения
Ну пускай читаем 16Кб
Придположим

Dmitry
21.10.2017
09:44:36

Google

Ievgenii
21.10.2017
09:44:42
После чего возвращаем управление приложению, может там какой-то таймер хочет сработать

Dmitry
21.10.2017
09:51:00
Я: "Тоесть условно говоря есть а) потока где работают файберы б) все остальные потоки Если встречается блокирующая операция то дергается тред из группы Б который выполняет само считывание данных, а тред из группы А просто перещелкивается"
Он: Ага примерно так
Он: запрос на чтение фиксируется и когда появится эвент из кернеля по этому сокету тогда поток из группы Б считывает
Он: Инчае ты просто начнешь локать по одному треду из Б на сокет, та же проблема
Он: 1 тред под диспетчера, К тредов для Файберов и М тредов под IO
Если я правильно понимаю, он говорит что есть еще какие-то потоки. куда делегируются блокирующие запросы.

Ievgenii
21.10.2017
09:53:38
Не совсем
Просто Файбер, если ты используешь шедулер, порождает отдельный поток, скорее всего, и все файберы выполняет в нем
Или в них!
Их может быть более одного
Чтобы не блокировать основной поток

Andrey
21.10.2017
09:54:42
смотри. есть у нас файберы, в одном из них делаем запрос к БД, асинхронный. после него делаем yeld(), что бы дать поработать другим файберам, так как, пока результат не получили, далтать этому файберу нечего, только ждать результат. затем, когда в следующий раз переключаемся в этот файбер, проверяем, если результат полуцчен - обрабатываем, если нет - опять yeld()

Ievgenii
21.10.2017
09:54:43
Но если ты в файбере сделаешь блокирующую операцию, самый простой способ - какой-то слип
То ты заблокируешь тот тред, в котором выполняется этот файбер
смотри. есть у нас файберы, в одном из них делаем запрос к БД, асинхронный. после него делаем yeld(), что бы дать поработать другим файберам, так как, пока результат не получили, далтать этому файберу нечего, только ждать результат. затем, когда в следующий раз переключаемся в этот файбер, проверяем, если результат полуцчен - обрабатываем, если нет - опять yeld()
Да

Ievgenii
21.10.2017
09:55:47
Ну или можно это сделать без файберов, а на колбеках.
Но тогда код не выглядет как синхронный
Вот и все

Dmitry
21.10.2017
09:56:04
смотри. есть у нас файберы, в одном из них делаем запрос к БД, асинхронный. после него делаем yeld(), что бы дать поработать другим файберам, так как, пока результат не получили, далтать этому файберу нечего, только ждать результат. затем, когда в следующий раз переключаемся в этот файбер, проверяем, если результат полуцчен - обрабатываем, если нет - опять yeld()
Так я понял, что файберы нужны чтобы не лочить тред в котором все выполняется. Но я правильно понимаю, что они просто операции считывания данных на другие треды делегируют?

Andrey
21.10.2017
09:56:37
или например, в файберах делешь http запросы. отослал запрос, проверяешь состояние сокета - если ответ не пришел, то опять таки, ждать нечего, делаешь yeld. и так проверяешь постоянно, если ответ пришел - обрабатываешь

Ievgenii
21.10.2017
09:56:44
Это зависит от того, используешь ли ты шедулер

Andrey
21.10.2017
09:56:45
нет
зачем им делегировать операции чтения в другие треды

Google

Ievgenii
21.10.2017
09:57:08
Если используешь шидулер, то этот файбер может выполняться в другом треде

Andrey
21.10.2017
09:58:37
файберы это просто возможноть переключать поток выполнения там, где у тебя появляется простой

Ievgenii
21.10.2017
09:58:55
https://dlang.org/phobos/std_concurrency.html#.FiberScheduler
Это будет в основном потоке

Dmitry
21.10.2017
09:59:36
@asan13 а про какие тогда треды Ольшанский говорит из группы Б?

Andrey
21.10.2017
09:59:56
это из твоей цитаты?

Dmitry
21.10.2017
10:00:30
да

Ievgenii
21.10.2017
10:00:36
А вот этот https://dlang.org/phobos/std_concurrency.html#.ThreadScheduler
Он делает, как я понимаю, отдельный тред и выполняет твой код, который тоже может быть файбером, в отдельном потоке

Admin
ERROR: S client not available

Andrey
21.10.2017
10:02:15
да
ну можно по разному организовать выполнение, зависит от конкретной программы. в простом случае, у тебя есть один нативный поток с файберами. но ничто не мешает насоздавать потоков, в ни х файберы, и перещелкивать-передавть, и что угодно.
может ты хочешь выделить отдельный тред для каких либо действий. файбер-шедулер не смотрел, наверно это какая то обертка для упрощения. но суть yeld()/call() и неблокирующего чтения именно в этом - проверяешь - если будет блокировка - делаешь yeld(). а там хоть в другом потоке читать пытайся, хоть в в этом позже, это уже детали

Ievgenii
21.10.2017
10:10:09
Нужно понять, что файбер не даёт асинхронность, он просто позволяет приостановить выполнения некой функции до тех пор, пока тебе не понадобится ее продолжить
Вот и все
Это некая надстройка над генератором

Andrey
21.10.2017
10:11:35
ну да.

Ievgenii
21.10.2017
10:14:58
А в каком потоке ты его запустиш (файбер) - это уже твоё дело

Andrey
21.10.2017
10:56:17
поток группы Б ожидает завершения асинхронных операций и о них сообщает в основные потоки
в vibe.d так сделано
С точки зрения файбера выполняется блокирующая операция. Но на самом деле операция выполняется асинхронно в другом потоке.

Google

Andrey
21.10.2017
10:59:18
В это время выполняются другия файберы. А когда приходит уведомление о завершении асинхронной операции, то ожидающий файбер продолжает работу

Dmitry
21.10.2017
14:55:17

Ievgenii
21.10.2017
14:57:46
Ну чтобы он не заблокировался, нужно работать с не блокирующими сокетами


Dmitry
21.10.2017
17:06:09
Так ну вот допустим функция из исходников vibed:
alias read = Stream.read;
size_t read(scope ubyte[] dst, IOMode)
{
assert(this.readable);
size_t len = dst.length;
while (dst.length > 0) {
enforce(dst.length <= leastSize);
auto sz = min(dst.length, 4096);
enforce(() @trusted { return .read(m_fileDescriptor, dst.ptr, cast(int)sz); } () == sz, "Failed to read data from disk.");
dst = dst[sz .. $];
m_ptr += sz;
yield();
}
return len;
}
Как оно получается будет работать?
поток группы Б ожидает завершения асинхронных операций и о них сообщает в основные потоки
Так. Тоесть все же есть еще потоки?
Получается картина следующая. Рассматриваем случай когда библиотеки построены с рассчетом на ассинхронность.
Есть основной поток (А) приложения. Он просто один за другим молотит функции одна за другой ничего не зная о их природе. Внутри самих функций предусмотрен неблокирующий механизм работы тоесть если ей нужно какой-то IO она стартует в фоновом потоке, а файберу помечает что данные скоро будут. Потом когда управление к нему возвращается он уже получает данные


Andrey
21.10.2017
17:33:35
ну а что непонятно в примере кода? ты правда взял специфичный случай, чтение из файла

Dmitry
21.10.2017
17:36:36
вот мы вызываем функцию read. В какой момент начинается чтение и в какой момент идет перещелкивание на другой файбер. После того как чтение начато оно будет в другом потоке идти?

Andrey
21.10.2017
17:41:49
конкретно в этом коде, мы с цикле вызываем системный read, который вычитывает максимум 4096 байт за раз, и отдает управление затем. на другой файбер перещелкивание идет в yeld, как ни странно))
то есть перещелкиваемся после каждой операции чтения
поскольку читаем из файла, то никогда не будет блокировки в read
а как этот код используется, хз, надо вайб смотреть
т.е на всякий, неоднозначно выразился, переключение не в самом системном read естественно, в коде ниже. а то вдруг не так поймешь)

Dmitry
21.10.2017
17:46:23
вызываем блокирующее чтение, но оно оказывается не блокирующим потому что читает 4096 байт и возвращает управление в функцию?

Andrey
21.10.2017
17:46:49
да. потому что читаем из файла
то есть данные всегда доступны, либо вычиали все.

Dmitry
21.10.2017
17:47:24
а в какой момент мы дочитаем его до конца? Типа мы же уже вернули что-то в функцию в которой был read вызван

Andrey
21.10.2017
17:50:07
до конца дочитали, когда dst.length == 0. перед чтеием она равна длине файла. там в цикле несколько мутная логика на первый взгляд
короче, есть у нас файл 1 мег длиной. читаем из него порциями по 4096 байт, и отдаем управление после каждого чтения

Dmitry
21.10.2017
17:53:06
foo()
{
data = read("foo.txt");
process(data);
}
Вот мы вызвали функцию чтения. Она при запуске как будет работтать? Мы же не сможем process() запустить т.к. данные не до конца прочитали

Andrey
21.10.2017
17:54:40
будет, потому что ты до process дойдешь, тоолько когда выйдешь из цикла, и затем из функции
если этот foo в файбере выполняется. в read будет постоянно происходить переключение, пока не вычитаем файл. затем только до process доберемся
вот ты хаял книжку Али, лучше б почитал там главу про файберы))