Вызов функции синхронизации асинхронно для отзывчивости интерфейса - PullRequest
0 голосов
/ 02 марта 2019

У меня есть метод синхронизации GetReports(), возвращаемое значение которого будет использоваться для установки источника данных элемента управления пользовательского интерфейса.Это может занять некоторое время, чтобы бежать.Это идиоматический способ назвать его асинхронно следующим образом?

var l = new List<...>();
await Task.Run(() => l = GetReports().ToList());
UIControl.DataSource = l;

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Вы должны использовать Microsoft Reactive Framework (также известный как Rx) - NuGet System.Reactive.Windows.Forms и добавить using System.Reactive.Linq; - тогда вы можете сделать это:

IDisposable subscription =
    Observable
        .Start(() => GetReports().ToList())
        .ObserveOn(UIControl)
        .Subscribe(list => UIControl.DataSource = list);

Это приятно перемещает в новый поток, а затем вытягивает егоназад перед обновлением DataSource.

Если вам нужно отменить до его завершения, просто позвоните subscription.Dispose();.

Если ваш звонок на GetReports можно отменить, то вы можете сделать это:

IDisposable subscription =
    Observable
        .FromAsync(ct => GetReports(ct))
        .Select(x => x.ToList())
        .ObserveOn(UIControl)
        .Subscribe(list => UIControl.DataSource = list);

Вызов subscription.Dispose() теперь также отменяет задачу.

0 голосов
/ 02 марта 2019

Если вы хотите реагировать на UI и запускать длительную рабочую нагрузку ЦП (а не масштабируемость как таковую), тогда это нормально и добьется того, чего вы хотите.По сути это будет

  1. Создать новый поток (термин используется свободно)
  2. Создать продолжение
  3. Вернуть поток, который его вызывает (в вашем случае поток пользовательского интерфейса)
  4. Выполнить рабочую нагрузку
  5. Запустить продолжение
    • 5a Выполнить все после await в потоке, который вы вызвали

Хотя Задачи не являются потоками, вы обнаружите, что они украдут поток из Пулов потоков , чтобы выполнить вашу рабочую нагрузку, и освободят Пользовательский интерфейс до его завершения

Вы также можете сделать то же самое со старым стилем Task.Run и ContinueWith.

Также существует другая школа мысли, что есливы используете TaskFactory.StartNew с TaskCreationOptions как LongRunning, это намекает на значение по умолчанию TaskScheduler, что вы хотите создать поток, внешний по отношению к Пулу потоков .Это дает преимущество, оставляя Thread Pool с большим количеством ресурсов.

Говоря о том, что TaskFactory.StartNew - великий папа Task методов создания, он имеетего собственные причуды, и вы, вероятно, должны использовать его, только когда вы чувствуете необходимость сделать это.Я бы просто придерживался того, что у вас есть.

Последнее примечание, хотя кажется хорошей идеей обернуть эту рабочую нагрузку в метод и назвать ее async, как правило, это не очень хорошая идея;и если вы должны обернуть, лучше всего позвонить решать эти вещи.Итак, еще раз вы делаете правильные вещи. Стивен Клири рассказывает о Fake Async и Async Wrappers и причинах, по которым вам не нужно делать это в

Task.Run Этикет и правильное использование

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...