【问题标题】:Reduce Task Parallel Library "Boilerplate"减少任务并行库“样板”
【发布时间】:2014-05-30 04:13:40
【问题描述】:

我的团队第一次使用任务并行库,我的同事想出了一些代码,如下所示。我们正在运行一些东西,然后使用该数据发出进一步的服务器请求(名称中带有Async 的方法),然后使用从该服务器调用返回的数据来获取更多数据。加载完所有这些后,UI 上的一些项目(通常是组合框)会更新(在名称中带有 Returned 的方法中),用户可以将其用于过滤器。

基本上,我们确定用户可以访问哪些公司,然后根据该信息,我们为数据加载更多“过滤器”(加载一些默认值),然后从默认视图加载数据。

虽然代码有效,但似乎有很多重复的代码,我想知道是否可以使用扩展方法或其他代码更改来减少执行此类操作所需的代码量。

Private Sub GetAndLoadViewData()
    Dim noCancelToken = CancellationToken.None
    Const attachToParent As TaskContinuationOptions = TaskContinuationOptions.AttachedToParent

    Task.Factory.StartNew(
        Sub()
            'fire off child tasks 
            Task.Factory.StartNew(Function() GetCompaniesAsync()).ContinueWith(
                Sub(t As Task(Of List(Of Company))) CompaniesReturned(t), noCancelToken, attachToParent, UiSyncContext)

            Task.Factory.StartNew(Function() GetUserAsync()).ContinueWith(
                Sub(t As Task(Of User)) UserReturned(t), noCancelToken, attachToParent, UiSyncContext)
        End Sub).ContinueWith(
            Sub(prevTask)
                'these tasks depend on the success of the previous task
                If Not prevTask.IsFaulted Then
                    Task.Factory.StartNew(Function() GetFiltersAsync()).ContinueWith(
                        Sub(t As Task(Of List(Of Filter))) FiltersReturned(t), noCancelToken, attachToParent, UiSyncContext)
                Else
                    'Rethrow the exception from the previous task if an exception occurred
                    Throw prevTask.Exception
                End If
            End Sub).ContinueWith(
                Sub(prevTask)
                    'these tasks depend on the success of the previous task
                    If Not prevTask.IsFaulted Then
                        Task.Factory.StartNew(Function() GetDataAsync(CurrentCompany, CurrentFilters)).ContinueWith(
                            Sub(t As Task(Of List(Of Data))) DataReturned(t), noCancelToken, attachToParent, UiSyncContext)

                    Else
                        'Rethrow the exception from the previous task if an exception occurred
                        Throw prevTask.Exception
                    End If
                End Sub).ContinueWith(
                    Sub(prevTask)
                        If prevTask.IsFaulted Then
                            View.HandleFatalException(prevTask.Exception.InnerExceptions.First())
                        Else
                            View.DisplayData()
                        End If
                    End Sub, UiSyncContext)
End Sub

我会注意到,由于业务原因,我们目前只能使用 .NET Framework 4.0。

如果需要更多信息,请告诉我。

【问题讨论】:

    标签: .net vb.net task-parallel-library


    【解决方案1】:

    我正是为此目的构建了Rackspace Threading Library(开源,Apache 2.0 许可)。

    另一种选择是使用Microsoft Async 包,允许您在.NET 4.0 代码库中使用async/await


    阅读您帖子中的代码对我来说有点挑战性。我做了一些假设,特别是所有以Async 结尾的方法都返回TaskTask<T>(根据Task-based Asynchronous Pattern (TAP) 准则)。

    以下是我提到的线程库的结果,采用 C# 语法。 ThenSelect 方法的行为类似于常规的顺序代码 - 一旦一个异常被抛出,所有剩余的代码都会被取消。 Finally 扩展方法的执行与前件的最终状态无关(包括已取消)。 Then 方法执行一个返回Task 的委托,然后等待该任务完成(类似于Unwrap 或您对AttachedToParent 的使用)。 Select 方法只是执行一个同步的代码块,它可能返回值,也可能不返回值。

    Task[] initialTasks =
    {
        GetCompaniesAsync().Select(task => CompaniesReturned(task)),
        GetUserAsync().Select(task => UserReturned(task))
    }
    
    TaskEx.WhenAll(initialTasks)
        .Then(_ => GetFiltersAsync().Select(task => FiltersReturned(task)))
        .Then(_ => GetDataAsync(CurrentCompany, CurrentFilters).Select(task => DataReturned(task)))
        .Select(_ => View.DisplayData())
        .Finally(
            task =>
            {
                if (task.IsFaulted)
                    View.HandleFatalException(task.Exception.InnerExceptions.First());
            });
    

    TaskEx.WhenAll 方法不是库的一部分,但您可以按如下方式实现它:

    public static Task<Task[]> WhenAll(params Task[] tasks)
    {
        return Task.Factory.ContinueWhenAll(tasks, completed => completed);
    }
    

    还请注意,在 C# 中,task =&gt; FooReturned(task) 形式的各种表达式可以仅替换为 FooReturned,但我选择保留较长的形式,以便读者清楚 FooReturned 实际上是您的方法之一你正在打电话。

    【讨论】:

      猜你喜欢
      • 2019-04-27
      • 2016-09-22
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多