2016-06-30 4 views
5

Я читал много статей об асинхронном программировании, но я не уверен в одном. У меня есть сторонняя библиотека winrt, написанная на C++, и я хочу ее обернуть. Итак, теперь у меня есть:Использование Task.Run для синхронного метода в службе

public Task LoginAsync(){ 
return Task.Run(winrtLibrary.Login();) 
} 

По словам Стивена Клири и Стивена Тубо, это нехорошее решение. Но когда я использую метод синхронно, мой пользовательский интерфейс не будет реагировать и будет заблокирован. Лучше ли выставлять метод службы синхронно, а в пользовательском интерфейсе используется Task.Run?

+0

Что делает этот метод? Что-то долгое, что блокирует ваш интерфейс? Тогда ответ «да», запустите его в новой задаче. –

+0

Да, метод входа может быть длинным.Это зависит от сети и т. Д. Если я блокирую пользовательский интерфейс, я не могу отменить процесс входа в систему. – JuP

+1

Точка, которую сделал Стивен Клири, заключается в том, что 'Task.Run'« уничтожает »Thread для выполнения работы, а Threads - дорого. Однако ваша библиотека C++ НЕОБХОДИМА для работы Thread. Поэтому проблема заключается не столько в том, что «Task.Run» является злом. Но 'Task.Run' обычно скрывает проблему использования потоков. – Aron

ответ

3

Что Стивен Toub означает по

не используют Task.Run в реализации метода; вместо того, чтобы использовать Task.Run для вызова метода

, что вы не должны использовать Task.Run, чтобы скрыть ЦП работу за методами асинхронными (Task методы, возвращающие). Если вам нужно обернуть внешний код, скройте его за интерфейсом, который отражает то, что делает этот код. Любой асинхронный ввод-вывод может (и должен) отображаться как возвращаемые методы Task, а работа с привязкой к ЦП должна быть открыта с помощью соответствующего API. Пусть потребители вашего кода сами решат, как использовать этот код. Когда вы тоже пользуетесь потребителем, используйте Task.Run для запуска вашего синхронного кода (теперь завернутый и открытый через интерфейс) , где очень ясно, что вы выгружаете работу с привязкой к процессору. Например, в приложениях пользовательского интерфейса вы должны называть Task.Run на вашем уровне пользовательского интерфейса (и не глубоко в ваших BL или даже DA-слоях), где очень ясно, что пользовательский интерфейс разгружает работу с некоторыми процессорами.


Почему вы думаете, что я не должна вызывать Task.Run в BL? Что делать, если у меня есть ViewModel, который ссылается на сервисный уровень BL и BL (в моем случае это оболочка).

Я думаю, что подпись метода должна точно отражать то, что делает этот метод. Лучшее, что я могу сделать, это перенаправить вас обратно Cleary's article:

Когда разработчик видит два метода в качестве API winrtLibrary.Login() и winrtLibrary.LoginAsync(), конвенции является то, что они представляют собой естественно -асинхронный работа. Другими словами, разработчик ожидает, что winrtLibrary.LoginAsync() будет «естественной» реализацией и что winrtLibrary.Login() по существу представляет собой синхронный (блокирующий) эквивалент этой операции . Этот API подразумевает , что winrtLibrary.Login в какой-то момент будет иметь вызывающий поток в состоянии ожидания , поскольку он блокирует естественно-асинхронную операцию до .

Вы по-прежнему можете скрывать синхронный код за методом асинхронного вызова и следовать правилу Клири, если вы подписываете свой метод как public Task OffloadLoginToTheThreadPool(). Но я думаю (и, по-видимому, Клири тоже), что альтернатива простому вызову Task.Run из пользовательского интерфейса (или контроллера) - гораздо лучший подход, и он следует принципам Clean Code.

+0

Почему вы думаете, что я не должен называть Task.Run в BL? Что делать, если у меня есть ViewModel, который ссылается на сервисный уровень BL и BL (в моем случае это оболочка). – JuP

Смежные вопросы