powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Асинхронное блокирование ресурса по значению
25 сообщений из 43, страница 1 из 2
Асинхронное блокирование ресурса по значению
    #39690889
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Покритикуйте код, реализующий асинхронное блокирование ресурса по значению.

Пример использования:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
private static readonly Synchronizer<int> Sync = new Synchronizer<int>();

...

public async Task SomeWork(SomeModel model, CancellationToken cancellationToken)
{
    // блокируем, чтобы метод выполнялся монопольно для каждого model.Id
    using(await Sync.Lock(model.Id, cancellationToken)
    {
        ...
    }
}



Реализация.

Код: c#
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.
    public class Synchronizer<T>
    {
        private readonly object _lock = new object();
        private readonly Dictionary<T, SyncLock<T>> _syncLocks = new Dictionary<T, SyncLock<T>>();

        public async Task<IDisposable> LockAsync(T value, CancellationToken cancellationToken)
        {
            SyncLock<T> syncLock;
            lock (_lock)
            {
                if (!_syncLocks.TryGetValue(value, out syncLock))
                {
                    syncLock = new SyncLock<T>(this, value);
                    _syncLocks.Add(value, syncLock);
                }
                syncLock.Capture();
            }
            await syncLock.WaitAsync(cancellationToken).ConfigureAwait(false);
            return syncLock;
        }

        internal void Unlock(SyncLock<T> syncLock)
        {
            lock (_lock)
            {
                var capturedCount = syncLock.Release();
                if (capturedCount == 0) _syncLocks.Remove(syncLock.Value);
            }
        }
    }

    internal class SyncLock<T> : IDisposable
    {
        private readonly Synchronizer<T> _synchronizer;
        private readonly T _value;
        private readonly SemaphoreSlim _semaphore;
        private int _captureCount;


        #region Internal routines

        internal SyncLock([NotNull] Synchronizer<T> synchronizer, T value)
        {
            _synchronizer = synchronizer;
            _value = value;
            _semaphore = new SemaphoreSlim(1, 1);
        }

        internal Task WaitAsync(CancellationToken cancellationToken)
        {
            return _semaphore.WaitAsync(cancellationToken);
        }

        internal int Capture()
        {
            return ++_captureCount;
        }

        internal int Release()
        {
            _captureCount--;
            _semaphore.Release();
            return _captureCount;
        }

        #endregion


        #region Properties

        public T Value => _value;

        #endregion


        #region IDisposable

        /// <inheritdoc />
        public void Dispose()
        {
            _synchronizer.Unlock(this);
        }

        #endregion
    }
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692468
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hVostt
Код: c#
1.
2.
3.
4.
5.
6.
    // блокируем, чтобы метод выполнялся монопольно для каждого model.Id
    using(await Sync.Lock(model.Id, cancellationToken)
    {
        ...
    }
}




Это к примеру, но могу порекомендовать посмотреть на эту либу
https://github.com/StephenCleary/AsyncEx
Там много вспомогательных примитивов для работы с асинхронностью, от большого спеца по асинхронности (я по его книге как раз и изучал тему асинхронности - очень понятно все разъясняет).
В частности там есть и AsyncLock, с которым можно работать как в асинхронном режиме, так и в асинхронном.
https://github.com/StephenCleary/AsyncEx/tree/v4
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692483
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

Dispose может затянуться
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692494
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreЭто к примеру, но могу порекомендовать посмотреть на эту либу
https://github.com/StephenCleary/AsyncEx
Там много вспомогательных примитивов для работы с асинхронностью, от большого спеца по асинхронности (я по его книге как раз и изучал тему асинхронности - очень понятно все разъясняет).

Честно говоря, мне очень сильно не нравится код из этого репозитория, я полностью избегаю его использовать. Хотя всё, что там реализовано работает, и работает правильно, большие вопросы к эффективности реализации.

Ну и соответствующая статья есть на хабре, как найду, приложу сюда.

WaspNewCoreВ частности там есть и AsyncLock, с которым можно работать как в асинхронном режиме, так и в асинхронном.
https://github.com/StephenCleary/AsyncEx/tree/v4

Ну в моём коде тоже нормальный асинк лок на SemaphoreSlim, но я с радостью готов услышать, почему он здесь будет работать не эффективно.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692495
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRoshVostt,

Dispose может затянуться

Да, ведь там и происходит блокирование :)

А где ты видишь здесь проблему?
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692497
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

там идет разблокирование, а временем диспоз ты не управляешь
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692518
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRos,

Важны гарантии. Диспоз тут для удобства, чтобы не делать try/catch/finally.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692533
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

Надо как можно быстрее освободить ресурс. А так как хошь :)
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692535
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRos,

а try/catch там аж два раза для monitor вызывается
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692537
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в общем плохой, медленный, нерабочий код
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692583
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRosViPRos,

а try/catch там аж два раза для monitor вызывается

lock только при операциях со словарём, т.е. очень быстро. Я не знаю как это сделать ещё быстрее, ConcurrentDictionary тут не нужен, так как мне ещё счётчик надо инкрементить/декрементить атомарно совместно с извлечением записи из словаря.

ViPRosв общем плохой, медленный, нерабочий код

А как сделать быстрее? Мне нужен именно async lock ресурса.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692608
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

я, к сожалению, с async не работаю.
Просто всегда блокировка точечная операция и ее так обрамлять плохая идея.
А синхронную версию типа твоего я тут где то уже выкладывал и ты его видел.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692618
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttViPRosViPRos,

а try/catch там аж два раза для monitor вызывается

lock только при операциях со словарём, т.е. очень быстро. Я не знаю как это сделать ещё быстрее
Ты неправильно размышляешь. Ты сделал быстро распараллелив разные ресурсы, а насколько быстро происходит распараллеливание это вторично. Это обслуживающий код, и то что он обслуживает намного тяжелее его. В остальном быстрее monitor, т.е. критической секции внутри, только спинлоки, но они тормозят когда ядер проца не хватает.

Еще небольшой плюсик можешь поиметь при разведении данных разных потоков по разным кэш-линиям 20429620
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692626
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRosПросто всегда блокировка точечная операция и ее так обрамлять плохая идея.

Ты имеешь в виду using? Почему?

ViPRosА синхронную версию типа твоего я тут где то уже выкладывал и ты его видел.

Синхронную видел :) Но так как щас всё асинках, код приходится переписывать.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692628
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TТы неправильно размышляешь. Ты сделал быстро распараллелив разные ресурсы, а насколько быстро происходит распараллеливание это вторично. Это обслуживающий код, и то что он обслуживает намного тяжелее его. В остальном быстрее monitor, т.е. критической секции внутри, только спинлоки, но они тормозят когда ядер проца не хватает.

Монитор нельзя использовать в контексте асинхронной операции, так как он лочит поток, а надо лочить ресурс, да и C# не скомпилирует await внутри критической секции, именно по этой причине.

Тут как бы не про распараллеливание идёт речь, а про асинхронность.

Dima TЕще небольшой плюсик можешь поиметь при разведении данных разных потоков по разным кэш-линиям 20429620

В этом имеет смысл, если в кеш-линию попадает то, что процессор может предсказать. Например, при последовательной обработке массива данных, нехорошо будет если будет переключение не на границе линии. Но тут я не большой эксперт, лоу перфоманс только недавно меня стал интересовать :)
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692638
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttDima TТы неправильно размышляешь. Ты сделал быстро распараллелив разные ресурсы, а насколько быстро происходит распараллеливание это вторично. Это обслуживающий код, и то что он обслуживает намного тяжелее его. В остальном быстрее monitor, т.е. критической секции внутри, только спинлоки, но они тормозят когда ядер проца не хватает.

Монитор нельзя использовать в контексте асинхронной операции, так как он лочит поток, а надо лочить ресурс, да и C# не скомпилирует await внутри критической секции, именно по этой причине.
Почему? Ты внутри lock делаешь очень легкие операции, все по фэншую. Возможно я что-то не понял в твоем коде, но в целом криминала не вижу.

hVosttТут как бы не про распараллеливание идёт речь, а про асинхронность.
Ты разработчик виндовса и .net ? Если нет, то речь про распараллеливание. "асинхронность" это продвинутое распараллеливание от разработчиков ОС.

hVosttDima TЕще небольшой плюсик можешь поиметь при разведении данных разных потоков по разным кэш-линиям 20429620

В этом имеет смысл, если в кеш-линию попадает то, что процессор может предсказать. Например, при последовательной обработке массива данных, нехорошо будет если будет переключение не на границе линии. Но тут я не большой эксперт, лоу перфоманс только недавно меня стал интересовать :)
Об этом Рихтер упоминал, разведи на 64 байта счетчики разных потоков и считать они будут намного быстрее.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692640
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TПочему? Ты внутри lock делаешь очень легкие операции, все по фэншую. Возможно я что-то не понял в твоем коде, но в целом криминала не вижу.

Ок, спасибо :)

Dima TТы разработчик виндовса и .net ? Если нет, то речь про распараллеливание. "асинхронность" это продвинутое распараллеливание от разработчиков ОС.

Ну если считать IO-bound отдельным видом потоков, то да :)

Dima TОб этом Рихтер упоминал, разведи на 64 байта счетчики разных потоков и считать они будут намного быстрее.

А, теперь понял о чём ты :)) StructLayout+FieldOffset?
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692645
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttА, теперь понял о чём ты :)) StructLayout+FieldOffset?
Суть в том что если две переменных хранятся в одной кэшлинии, например
Код: c#
1.
2.
3.
4.
struct {
  int x;
  int y;
}


и два разных потока делают x++ и y++ соответственно, то это будет раз в 7-8 медленнее чем так
Код: c#
1.
2.
3.
4.
5.
struct {
  int x;
  byte buffer[64];
  int y;
}


Но это не точно, пишу по аналогии с С/С++, не уверен что в C# byte buffer[64] это массив внутри структуры, а не указатель на него.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692652
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttНу если считать IO-bound отдельным видом потоков, то да :)
Дай ссылку почитать про это. Может я чего не знаю.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39692669
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TНо это не точно, пишу по аналогии с С/С++, не уверен что в C# byte buffer[64] это массив внутри структуры, а не указатель на него.

Ну то есть так

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
[StructLayout(LayoutKind.Explicit)]
public struct struct1
{
    [FieldOffset(0)]
    public int x; 
    [FieldOffset(64)]
    public int y; 
}



byte buffer[64], кстати, не сдвинет позицию на 64 байта. Ну лан, это лирика :) Суть ясна.


Dima TДай ссылку почитать про это. Может я чего не знаю.

Наверное знаешь, на всякий

https://docs.microsoft.com/en-US/windows/desktop/FileIO/i-o-completion-ports
https://blog.stephencleary.com/2013/11/there-is-no-thread.html
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39693006
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttПокритикуйте код, реализующий асинхронное блокирование ресурса по значению.
В традиции и образе ресурса: код - гавно, афтор - му**к.
Да и кстати: куда уехал цирк? где ПТ?

По пунктам:
- кацелейшн как то странно выглядик. Если его словили то можно и без лока двигать, да ?
- overengenered. Можно и нужно просче. SemaphoreSlim не нужен.
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39693011
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikron- кацелейшн как то странно выглядик. Если его словили то можно и без лока двигать, да ?

Хорошее замечание, не хватает проверки на IsCanceled, хотя внутренняя реализация его должна тоже схавать, но здесь проверки не хватает.

Вообще, await lock в using уже не выглядит хорошим решением.

mikron- overengenered. Можно и нужно просче. SemaphoreSlim не нужен.

Другие варианты async lock?
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39693024
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Следующая версия :)
Изменился способ использования

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
private static readonly Synchronizer<int> Sync = new Synchronizer<int>();

...

public async Task SomeWork(SomeModel model, CancellationToken cancellationToken)
{
    // получаем объект блокировки для монопольных операций по model.Id
    using(var syncLock = await Sync.GetLock(model.Id))
    {
        // блокируем
        await syncLock.WaitAsync(cancellationToken);
        // делаем свои дела
        ...
    }
}



Код: c#
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.
    public class Synchronizer<T>
    {
        private readonly object _lock = new object();
        private readonly Dictionary<T, SyncLock<T>> _syncLocks = new Dictionary<T, SyncLock<T>>();

        public SyncLock<T> GetLock(T value)
        {
            lock (_lock)
            {
                if (!_syncLocks.TryGetValue(value, out var syncLock))
                {
                    syncLock = new SyncLock<T>(this, value);
                    _syncLocks.Add(value, syncLock);
                }
                syncLock.Capture();
                return syncLock;
            }
        }

        internal void Unlock(SyncLock<T> syncLock)
        {
            lock (_lock)
            {
                var capturedCount = syncLock.Release();
                if (capturedCount == 0) _syncLocks.Remove(syncLock.Value);
            }
        }
    }

    public class SyncLock<T> : IDisposable
    {
        private readonly Synchronizer<T> _synchronizer;
        private readonly T _value;
        private readonly SemaphoreSlim _semaphore;
        private int _captureCount;


        #region Internal routines

        internal SyncLock([NotNull] Synchronizer<T> synchronizer, T value)
        {
            _synchronizer = synchronizer;
            _value = value;
            _semaphore = new SemaphoreSlim(1, 1);
        }

        internal int Capture()
        {
            return ++_captureCount;
        }

        internal int Release()
        {
            _captureCount--;
            _semaphore.Release();
            return _captureCount;
        }

        #endregion


        #region Public methods

        public T Value => _value;

        public async Task WaitAsync(CancellationToken cancellationToken)
        {
            await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
            cancellationToken.ThrowIfCancellationRequested();
        }

        #endregion


        #region IDisposable

        /// <inheritdoc />
        public void Dispose()
        {
            _synchronizer.Unlock(this);
        }

        #endregion
    }
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39693041
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
            SyncLock<T> syncLock;
            lock (_lock)
            {
                if (!_syncLocks.TryGetValue(value, out syncLock))
                {
                    syncLock = new SyncLock<T>(this, value);
                    _syncLocks.Add(value, syncLock);
                }
                syncLock.Capture();


https://docs.microsoft.com/ru-ru/dotnet/csharp/whats-new/csharp-7#out-variables
...
Рейтинг: 0 / 0
Асинхронное блокирование ресурса по значению
    #39693047
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,
Чего добиться то хочешь?
...
Рейтинг: 0 / 0
25 сообщений из 43, страница 1 из 2
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Асинхронное блокирование ресурса по значению
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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