Здравствуйте, Sharov, Вы писали:
S>но сделать так на прямую нельзя. Как быть? Есть что-то стандартное\библиотечное? S>Тут что-то такое мелькало, но не найду сейчас...
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте.
S>А как в .net core обстоят дела с асинхронным локом, есть какой-нибудь примитив а-ля AsyncMonitor? S>Мне нужно S>
S>lock(syncObj)
S>{
S> await DoAsync()
S>}
S>
S>но сделать так на прямую нельзя. Как быть? Есть что-то стандартное\библиотечное? S>Тут что-то такое мелькало, но не найду сейчас...
Привет это известная проблема у тебя 2-а варианта использовать monitor на прямую, посмотри во что разворачивается lock (синтаксический сахар)
либо вот тебе ссылки на статью как это делается более навороченным способом
У меня примерно такая же проблема.
Есть функция сторонней библиотеки
public IDisposable AddMessageHandler<Tmessage>(string messageName, Action<Tmessage> handler)
{
return _hubProxy.On(messageName, message =>
{
var decoded = DataConverter.Decode<Tmessage>(message);
handler(decoded);
});
}
В ней надо написать свои Action<Tmessage> handler для разных событий, которые определяются string messageName.
При этом разного рода события, таких как получение цен, размещение своих ордеров, в случае если цены удовлетворяют условию , не должны мешать друг-другу, т.е. должны быть асинхронными, но события одни и те же, размещение ордеров, не должны быть одновременными, т.к. после каждого размещения изменяется баланс, значение которого используется при размещении ордеров. Думаю сделать просто: Action<Tmessage> handler для события "open_orders" написать
Action<string, Bittrex> AOrderBook = async (message)=>
{
//есть редко вызываемый, только когда есть совпадение условий await асинхронный метод и без lock, чтобы не мешать одновременному потоку цен
}
Попробовал, работает. Как происходит распознавание синхронный Action<string> или нет не знаю, одного async недостаточно потому await Task.Delay(1);. И код работает потому что нет await окончания работы Action, т.е. не вызывается EndInvoke. То что нет вызова EndInvoke у Action это стандарт для событий?
Здравствуйте, Sharov, Вы писали: S>1)Зачем это все делать асинхронно? S>2)Возможно, что блокирующая очередь будет чем-то полезна...
1. Если приходит информация с сервера, на сервер посылается запрос на выполнение некоторых действий. Если в это время не обрабатывать новые данные с сервера, то после выполнения сервером запроса, будут приходить устаревшие данные, которые были отложены к принятию из-за не асинхронности.
2. Не понял зачем блокирующая очередь.
Здравствуйте, Passerby, Вы писали:
P>Здравствуйте, Sharov, Вы писали: S>>1)Зачем это все делать асинхронно? S>>2)Возможно, что блокирующая очередь будет чем-то полезна... P>1. Если приходит информация с сервера, на сервер посылается запрос на выполнение некоторых действий. Если в это время не обрабатывать новые данные с сервера, то после выполнения сервером запроса, будут приходить устаревшие данные, которые были отложены к принятию из-за не асинхронности. P>2. Не понял зачем блокирующая очередь.
В целях синхронизации -- данные обрабатываются по мере поступления. Если не ошибаюсь, возможна разная
конфигурация читателей и писателей -- 1:n, n:n и т.д.
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте.
S>А как в .net core обстоят дела с асинхронным локом, есть какой-нибудь примитив а-ля AsyncMonitor? S>Мне нужно S>
S>lock(syncObj)
S>{
S> await DoAsync()
S>}
S>
S>но сделать так на прямую нельзя. Как быть? Есть что-то стандартное\библиотечное? S>Тут что-то такое мелькало, но не найду сейчас...
для костыля сойдет. Бест — практис это TaskScheduler с 1м или N рабочимими потоками для той логики которая должна тротлится в один или N потоков максимум. В общем случае. Вы таким образом разделяете ответственность.
А зачем завернули SemaphoreSlim в матрёшку?
Разве методы-расширения не справились бы?
Ну и, если требуется только асинхронная блокировка, то SemaphoreSlim — это из пушки по воробьям, слишком тяжеловесно, особенно в свете новомодных TaskValue.
В этом смысле SemaphoreSlim устарел.
Никогда так не делай. ))
Унутре вызывается RegisterWaitForSingleObject, а этого вызова надо избегать — он морозит по одному потоку на каждый такой хендл.
И что хреновее всего, здесь участвует межпоточная сигнализация уровня ОС, а этого в общем случае не требуется, т.к. вызывать асинхронное продолжение можно из текущего потока пула, что эффективнее на порядки.
Здравствуйте, IncremenTop, Вы писали:
S>>но сделать так на прямую нельзя. Как быть? Есть что-то стандартное\библиотечное? IT>Есть, но скорее всего у тебя неправильная архитектура, раз до такого доходит. Советую пересмотреть и обдумать.
Чегой-то? ))
Классический мьютекс — это очередь потоков к ресурсу (обрати внимание, что защищённый мьютексом сценарий назвают "сериализованным").
В кооперативной асинхронщине поверх пула потоков происходящее в точности аналогично, просто очередь переносится из недр ОС в код юзверского уровня исполнения.
Более того, почти всегда очередь можно обслуживать из того же потока, в котором ресурс отпускается, что исключит межпоточную сигнализацию, т.е. не приведёт к профанации кооперативной многозадачности юзверского уровня, ради которой весь этот огород async/await нагородили.
(ИМХО, async/await в управляемых средах — идиотизм сам по себе, бо сответствующая потоковая модель могла быть применена средой исполнения автоматически, без разметки ключевыми словами со стороны программера)
Г-но мамонта из 2012-го.
Сейчас стоит сделать очередь простых пар {callback:delegate, configuredAwait:bool}, без прокси-задач TaskCompletionSource, как по ссылке.
См IValueTaskSource.
Здравствуйте, vdimas, Вы писали:
V>Ну и, если требуется только асинхронная блокировка, то SemaphoreSlim — это из пушки по воробьям, слишком тяжеловесно, особенно в свете новомодных TaskValue. V>В этом смысле SemaphoreSlim устарел.
RegisterWaitForSingleObjectМетод помещает указанный делегат в очередь пула потоков. Рабочий поток будет выполнять делегат при возникновении одного из следующих событий:
Указанный объект находится в сигнальном состоянии.
Интервал времени ожидания истекает.
RegisterWaitForSingleObject Метод проверяет текущее состояние указанного объекта WaitHandle . Если состояние объекта не сигнальо, метод регистрирует операцию ожидания. Операция ожидания выполняется потоком из пула потоков. Делегат выполняется рабочим потоком, когда состояние объекта становится сигнальным или истекает интервал времени ожидания. Если timeOutInterval параметр имеет значение, отличный от 0 (ноль), а executeOnlyOnce параметр — false , таймер сбрасывается каждый раз, когда событие получает сигнал, или истекает интервал времени ожидания.
По твоему поток морозится на ожидании сигнала или таймаута.
И на каждый хендл свой поток?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Ночной Смотрящий, Вы писали:
V>>А зачем завернули SemaphoreSlim в матрёшку? V>>Разве методы-расширения не справились бы? НС>Методы расширения к чему?
Здравствуйте, Serginio1, Вы писали:
S>Ну судя по описанию вызовется делегат в пуле потоков.
Верно.
S>Ничего морозиться не будет
Ты же сам ниже оставил объяснение:
S>Операция ожидания выполняется потоком из пула потоков. Делегат выполняется рабочим потоком, когда состояние объекта становится сигнальным или истекает интервал времени ожидания. Если timeOutInterval параметр имеет значение, отличный от 0 (ноль), а executeOnlyOnce параметр — false , таймер сбрасывается каждый раз, когда событие получает сигнал, или истекает интервал времени ожидания. S>[/q]
S>По твоему поток морозится на ожидании сигнала или таймаута.
В одном из потоков пула будет сделан блокирующий вызов WinAPI WaitForSingleObject для соотв хендла, а после возврата из этого вызова будет вызван поданный колбэк.
S>И на каждый хендл свой поток?
Да, что малость забавно, ведь WaitForMultipleObjects может ожидать до 64-х хендлов.
Видать, не стали заморачиваться.