Лучший отвечающий
lock внутри async метода

Вопрос
-
Я не особо силен в многопоточном программировании. Поэтому вопрос: можно ли использовать lock внутри async метода. Вот так:
private Dictionary<string, ClientController> clients = new Dictionary<string, ClientController>(); private object locker = new object(); public async void Add(ClientController client) { await new Task(() => { lock (locker) { clients.Add(client.Id, client); } }); } public async Task<int> Count() { return await new Task<int>(() => { lock (locker) { return clients.Count; } }); }
если нельзя, то как правильно сделать асинхронную коллекцию, с потокобезопасным изменением?
- Изменено Гарифуллин Ильяс 24 сентября 2014 г. 13:55
24 сентября 2014 г. 13:53
Ответы
-
lock — это просто обёртка над Monitor.Enter и Monitor.Exit, так что использовать lock внутри async метода можно. Однако есть несколько вопросов касательно Вашего кода:
- Почему
public async void Add(...)
а неpublic async Task Add(...)
Как вызвавший метод сможет узнать о завершении работы, если Вы не возвращаете никакого объекта? -
await new Task(...)
Задачу Вы создали, но не запустили, так что ждать её можно вечно. - Зачем вообще использовать асинхронные методы, если всё, что Вы делаете, это создание и ожидание одной задачи?
public Task Add(ClientController client) { return Task.Factory.StartNew(() => { lock(locker) { clients.Add(client.Id,client); } }); } public Task<int> Count() { return Task.Factory.StartNew(() => { lock(locker) { return clients.Count; } }); }
- А есть ли вообще смысл использовать здесь асинхроннось? Расходы на создание задачи вполне могут превышать расходы на добавление элемента в коллекцию.
- Изменено PetSerAl 24 сентября 2014 г. 16:39
- Предложено в качестве ответа YatajgaModerator 27 сентября 2014 г. 10:25
- Помечено в качестве ответа Dmitriy VereshchakMicrosoft contingent staff, Moderator 29 сентября 2014 г. 8:16
24 сентября 2014 г. 16:38 - Почему
Все ответы
-
Я не особо силен в C#, но если я правильно понял работу lock, то да можно и в принципе нужно.
Причем сначала я было подумал, что при запросе Count блокировать поток не обязательно ибо это потокобезопасный запрос, но потом подумал, что в этот момент коллекция может быть изменена и Count будет не актуален. Выходит что код верен.
Ну пусть гуру C# еще подтвердят.
VB.Net - WPF, WinRT, WP
24 сентября 2014 г. 14:22Отвечающий -
lock — это просто обёртка над Monitor.Enter и Monitor.Exit, так что использовать lock внутри async метода можно. Однако есть несколько вопросов касательно Вашего кода:
- Почему
public async void Add(...)
а неpublic async Task Add(...)
Как вызвавший метод сможет узнать о завершении работы, если Вы не возвращаете никакого объекта? -
await new Task(...)
Задачу Вы создали, но не запустили, так что ждать её можно вечно. - Зачем вообще использовать асинхронные методы, если всё, что Вы делаете, это создание и ожидание одной задачи?
public Task Add(ClientController client) { return Task.Factory.StartNew(() => { lock(locker) { clients.Add(client.Id,client); } }); } public Task<int> Count() { return Task.Factory.StartNew(() => { lock(locker) { return clients.Count; } }); }
- А есть ли вообще смысл использовать здесь асинхроннось? Расходы на создание задачи вполне могут превышать расходы на добавление элемента в коллекцию.
- Изменено PetSerAl 24 сентября 2014 г. 16:39
- Предложено в качестве ответа YatajgaModerator 27 сентября 2014 г. 10:25
- Помечено в качестве ответа Dmitriy VereshchakMicrosoft contingent staff, Moderator 29 сентября 2014 г. 8:16
24 сентября 2014 г. 16:38 - Почему
-
1. да, вы правы, спасибо за поправку
3. в классе есть еще и другие методы, я показал только эти 2 чтобы не нагромождать вопрос, а еще есть удаление, проверка на существование, и возврат массива элементов, Select и Where как в linq
4. возможно и нет, я с многопоточностью не особо разобрался еще, идея была сделать потокобезопасную коллекцию которая не блокировала бы поток в котором она вызывается. Я прочитал недавно про модель акторов, и захотел реализовать нечто похожее в данном случае. Возможно глупость сморозил :)
25 сентября 2014 г. 4:47 -
Использовать асинхроннось в данном случае лишено всякого смысла. Использовать возможности языка/платформы лишь только потому, что они есть – плохая практика.
Сделаем содержимое сообщества лучше, вместе!
25 сентября 2014 г. 5:46Модератор -
private Dictionary<string, ClientController> clients = new Dictionary<string, ClientController>();
private IDicitionary<string, ClientController> clients = new ConcurrentDictionary<string, ClientController>();
25 сентября 2014 г. 6:41 -
Вообще если нужно лочить в асинк методах, то можно юзать такое - Async Lock25 сентября 2014 г. 9:02