C # имеют асинхронный функцию синхронной функции или синхронной функции функции ASYNC
-
12-12-2019 - |
Вопрос
Я пишу библиотеку C # .NET 4.5 для выполнения общих операций базы данных SQL (резервное копирование, восстановление, выполнение скрипта и т. Д.). Я хочу иметь как синхронные, так и асинхронные функции для каждой операции, так как эта библиотека будет использоваться как приложениями консоли, так и для GUI, но я не хочу дублировать код везде. Так как я вижу это, у меня есть два варианта:
-
Написать код, который выполняет работу в синхронной функции, а затем просто оберните его в задаче для Async-функции, как так:
public void BackupDB(string server, string db) { // Do all of the work and long running operation here } public async Task BackupDBAsync(string server, string db) { await Task.Factory.StartNew(() => BackupDB(server, db)).ConfigureAwait(false); }
-
Напишите код, который выполняет работу в асинхронной функции, и вызовите его из синхронной функции, используя .Wait ():
public async Task BackupDBAsync(string server, string db) { // Do all of the work and long running operation here, asynchronously. } public void BackupDB(string server, string db) { BackupDBAsync(server, db).Wait(); // Execution will wait here until async function finishes completely. }
- один вариант лучше другого? Это одна лучшая практика? Или есть ли другие (лучшие) альтернативы?
Я знаю, что одно предупреждение для использования .wait () состоит в том, что все заявления avait в функции async должны использовать .configureawait (false), чтобы избежать тупиков ( Как обсуждалось здесь ), но с тех пор, как я пишу библиотеку, которая никогда не должна получить доступ к интерфейсу Или WebContext Я в безопасности, чтобы сделать это.
Обратите внимание, что библиотека SQL обычно также имеет как синхронные, так и асинхронные функции, которые могут быть использованы, поэтому, если выполнение работы в функции синхронизации, я бы позвонил их функцию синхронизации, а если выполнять работу в Async Функция, я бы назвал свою async функцию.
Мысли / предложения ценятся.
- Редактировать: я также опубликовал этот вопрос на форумах MSDN здесь , чтобы попытаться получить официальный ответ MS -
Решение
Я хочу иметь как синхронные, так и асинхронные функции для каждой операции, поскольку эта библиотека будет использоваться как приложениями консоли, так и для GUI, но я не хочу дублировать код везде.
Лучший ответ: не.
Стивен Toub имеет два отличных сообщения в блоге на этой теме:
.
- Должен ли я разоблачить асинхронные обертки для синхронных методов?
- Должен ли я выставить синхронные обертки для асинхронных методов?
Он рекомендует разоблачить асинхронные методы как асинхронные, а синхронные методы как синхронные.Если вам нужно разоблачить оба, затем инкапсулировать общие функции в частных (синхронных) методах и дублировать различия асинхронизации / синхронизации.
Другие советы
У меня была похожая ситуация, когда некоторые приложения необходимы, необходимые данные, которые будут загружаться синхронно и другие ASYC.Я решил создать интерфейс, который я позвонил My DataLoader:
public interface IIMViewModelDL {
void LoadProjects(AssignProjects callback);
}
.
Обратный вызов TranseProjects - это просто простой делегат, который принимает возвращенный список проектов:
public delegate void AssignProjects(IEnumerable<Project> results);
.
Теперь красота этого состоит в том, что вы можете работать с интерфейсом, не зная, имеете ли вы в синхронизации или Async.
3 класса создаются: одна база, одна синхронизация и один async:
public abstract class BaseViewModelDL {
protected IEnumerable<Project> LoadProjects() {
BaseServiceClient client = new BaseServiceClient();
return client.Projects();
}
public class SynchronousViewModelDL : BaseViewModelDL, IIMViewModelDL {
public void LoadProjects(AssignProjects callback) {
callback(base.LoadProjects());
}
public class AsyncIMViewModelDL : BaseViewModelDL, IIMViewModelDL {
public void LoadProjects(AssignProjects callback) {
BackgroundWorker loadProjectsAsync = new BackgroundWorker();
loadProjectsAsync.DoWork += new DoWorkEventHandler(LoadProjectsAsync_DoWork);
loadProjectsAsync.RunWorkerCompleted += new RunWorkerCompletedEventHandler(LoadProjectsAsync_RunWorkerCompleted);
loadProjectsAsync.RunWorkerAsync(callback);
}
void LoadProjectsAsync_DoWork(object sender, DoWorkEventArgs e) {
var results = new ObservableCollection<Project>(base.LoadProjects());
e.Result = new object[] { results, e.Argument };
}
void LoadProjectsAsync_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
AssignProjects callback = (AssignProjects)((object[])e.Result)[1];
IEnumerable<Project> results = (IEnumerable<Project>)((object[])e.Result)[0];
callback(results);
}
.
Теперь в вашем приложении вы можете решить, как вы хотите загрузить данные ... Это может быть введено через контейнер IOC, но жестко закодирован для демонстрационных целей:
private ViewModelDataLoaders.IIMViewModelDL dataLoader = new ViewModelDataLoaders.AsyncIMViewModelDL();
.
Теперь ваш код вызова выглядит одинаково, и нет в том, является ли он async или Sync:
private void LoadProjects() {
dataLoader.LoadProjects(
delegate(IEnumerable<Project> results) {
Projects = new ObservableCollection<Project>(results);
});
}
.
Я использую это регулярно для тестирования устройства (синхронизации), приложений WPF (ASYNC) и консольных приложений (синхронизация).
Там, кажется, не является точкой просто отметить метод Async без использования ждут. Маркировка его как Async не делает его асинхронным, это позволяет вам использовать ждет (код, выполненный в aquast, это то, что происходит асинхронно, а затем остальная часть асинхронизации также будет выполняться асинхронно) в организме метода: < / P >.
Как правило, метод, модифицированный ключевым словом Async, содержит по меньшей мере одно ждут выражения или оператора. Способ проходит синхронно, пока он не достигнет первого выражения ждут, в какой момент он приостановлен до тех пор, пока ожидаемая задача не будет завершена. Тем временем контроль возвращается к абоненту метода. Если метод не содержит ждут выражения или оператора, то он выполняет синхронно. Предупреждение о компиляторе предупреждает вас с любыми асинкоми методами, которые не содержат ждут, потому что эта ситуация может указывать на ошибку. Для получения дополнительной информации см. ПРЕДУПРЕЖДЕНИЕ COMBILER CS4014.
от: async / P >.