2

我有这样的问题。例如,我使用 mvvm 模式创建动态自定义 userControl。所以我发送了一个命令来创建一个 userControl。所以创作看起来像

private async Task<bool> OnAddUserControl1(List<ALV_VM_ADWERT> control)
{
    try
    {
        _cancellationTokenSource = new CancellationTokenSource();
        var userControl = _userControlsContainer.CreateUserControl1(control);

        var task1 = Task.Factory.StartNew(() =>
        {
            userControl.ViewModel.InOperationEvent += OnUsercontrolInOperationChanged;
            userControl.ViewModel.ValueTypeChangedEvent += OnValueTypeChanged;
            userControl.ViewModel.SetExpandableName += OnSetExpandableName;
        }, _cancellationTokenSource.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext());

        var task2 = Task.Factory.StartNew(() => FinalCreatingStep(userControl, control[0].RAUMNAME.Trim()), _cancellationTokenSource.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext());
        await Task.WhenAll(task1, task2);
        return true;
    }
    catch (Exception)
    {
        return false;
    }                
}

我的问题是 - 创建子任务是否有意义,或者最好有没有子任务的代码?如果答案是肯定的,那么我应该让所有方法异步吗?如果不是,我不应该使哪些方法异步?

4

3 回答 3

4

这些事件订阅真的需要异步吗?您可能过于努力地使用异步代码。

用户控件构造函数通常是最耗时的部分,必须在 UI 线程上完成。异步操作一般只有在涉及某种形式的 IO 或处理时才需要;

  • 读取文件
  • 写入文件
  • 处理大型数据集
  • 跨越进程边界与服务器或连接设备对话

简而言之,异步任务在这里可能是矫枉过正。

于 2013-10-17T08:52:08.537 回答
3

创建子任务是否有意义,或者最好有没有子任务的代码?

这取决于您的要求。如果您的 UI 将长时间阻塞(冻结),您必须创建子任务,否则不会!

如果答案是肯定的,那么我应该让所有方法异步吗?如果不是,我不应该使哪些方法异步?

这也取决于您的要求和您的 .Net 版本。如果您使用的是 .NET 4.5,最简单的方法是使用 Async await。如果您使用的是 .Net 3.5,而不仅仅是使用 Task。如果 .Net 2 使用 BackgorundWorker,则使用 Thread 类。只有异步方法必须使用 async 这个词。其他方法您不必更改它们。换句话说,只有阻止 UI 的方法。

于 2013-10-17T09:03:24.297 回答
2

您当前的代码没有任何意义。

asyncUI 应用程序中的代码重点是响应能力——即将长时间运行的操作移出 UI 线程。正如@Gusdor 指出的那样,大多数用例async都是基于 I/O(或基于事件)的操作,您不想阻塞 UI 线程只是为了等待某些结果。另一个用例是当您有一些 CPU 密集型工作要做,但又不想占用 UI 线程;在这种情况下,您可以使用Task.Run.

但是在您的代码中,您使用 调用StartNewTaskScheduler.FromCurrentSynchronizationContext这意味着您的“子”任务将在 UI 线程上执行。因此,您OnAddUserControl1只是在启动将在同一线程上运行并异步等待它们完成的任务。这是一种非常复杂的无所事事的方式。

在我们讨论 的主题时StartNew,还有许多其他问题:

  1. 代码在传递 aCancellationToken时从未在委托中观察到它。
  2. 代码指定AttachedToParent了哪些是不正确的await- 兼容任务。
  3. 如上所述,代码正在传递TaskScheduler将在 UI 线程上运行委托的 a。

如果你需要使用后台(线程池)任务,你应该使用Task.Run代替Task.Factory.StartNew; 我会在我的博客上详细介绍。

async所以对于这个例子,使用or根本没有意义await

开始使用的最佳方法async是首先识别 I/O 绑定(或事件驱动)部分(例如,HTTP 请求、数据库调用),制作它们async,然后在调用堆栈中向上工作。

于 2013-10-17T13:07:33.907 回答