我的同事是否复制了任务的确切行为。

发布于 2025-02-12 18:01:19 字数 2349 浏览 0 评论 0 原文

在审查承包商的工作时,我遇到了以下扩展方法:

public static class TaskExtensions
{
    public static async Task<IEnumerable<TResult>> WhenAllSynchronousExecution<TResult>(this IEnumerable<Task<TResult>> tasks, CancellationToken token = default(CancellationToken))
    {
        var results = new List<TResult>();
        var exceptions = new List<Exception>();
        foreach (var task in tasks)
        {
            if (task == null)
            {
                throw new ArgumentNullException(nameof(tasks));
            }
            
            if (token.IsCancellationRequested) {
                exceptions.Add(new OperationCanceledException("Tasks collection cancelled", token));
                break;
            }

            try
            {
                results.Add(await task);
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }
        
        if (exceptions.Any()) {
            throw new AggregateException(exceptions);
        }
        
        return results;
    }
}

这看起来正是 task.whenall&lt; tresult&gt; 引用这些话:

何时呼叫(ienumerable&lt; task&gt;)方法不会阻止调用线程。但是,对返回结果属性的调用确实会阻止调用线程。

如果所提供的任何任务以故障状态完成,则返回的任务也将在故障状态下完成,在此,其例外将包含从每个提供的任务中的一组未包装异常的聚合。

如果未提供的任务都没有故障,但其中至少一个被取消,则返回的任务将以取消状态结束。

如果任何任务都没有故障且没有取消任务,则结果任务将以rantocompletion状态结束。返回任务的任务属性将设置为一个数组,该数组包含所提供任务的所有结果,以与提供的顺序相同(例如,如果输入任务数组包含T1,T2,T3,则输出任务的任务,则输出任务的任务.Result属性将返回一个tresult [],其中arr [0] == t1。result,arr [1] == t2.Result,and arr [2] == t3.Result)。

如果任务参数不包含任何任务,则返回的任务将在返回给呼叫者之前立即过渡到rantocoltetion状态。返回的tresult []将是0个元素的数组。

因此,对我来说,似乎他们已经重新创建了一种现有方法。唯一的区别似乎是检查 concellationToken 的检查,但是我看不到Mych添加的值(代码中未使用)。也许这是一种扩展方法,但也没有在代码中使用(称为 var task = taskextensions.whenallsynchronyousexecution(tasks);

,但该同事非常“敏感”。所以我需要挑出战斗。那么,这只是任务的自定义,微薄的娱乐。

When reviewing work by a contractor, I came upon the following extension method:

public static class TaskExtensions
{
    public static async Task<IEnumerable<TResult>> WhenAllSynchronousExecution<TResult>(this IEnumerable<Task<TResult>> tasks, CancellationToken token = default(CancellationToken))
    {
        var results = new List<TResult>();
        var exceptions = new List<Exception>();
        foreach (var task in tasks)
        {
            if (task == null)
            {
                throw new ArgumentNullException(nameof(tasks));
            }
            
            if (token.IsCancellationRequested) {
                exceptions.Add(new OperationCanceledException("Tasks collection cancelled", token));
                break;
            }

            try
            {
                results.Add(await task);
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }
        
        if (exceptions.Any()) {
            throw new AggregateException(exceptions);
        }
        
        return results;
    }
}

To this looks to be exactly what Task.WhenAll<TResult> already does. quote the remarks:

The call to WhenAll(IEnumerable<Task>) method does not block the calling thread. However, a call to the returned Result property does block the calling thread.

If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.

If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.

If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state. The Task.Result property of the returned task will be set to an array containing all of the results of the supplied tasks in the same order as they were provided (e.g. if the input tasks array contained t1, t2, t3, the output task's Task.Result property will return an TResult[] where arr[0] == t1.Result, arr[1] == t2.Result, and arr[2] == t3.Result).

If the tasks argument contains no tasks, the returned task will immediately transition to a RanToCompletion state before it's returned to the caller. The returned TResult[] will be an array of 0 elements.

So to me it seems they've recreated an existing method. The only difference seems to be the checking of the CancellationToken, but I don't see mych added value there (it's not used in the code). And maybe that it's an extension method, but that's also not used in the code (it's called like var task = TaskExtensions.WhenAllSynchronousExecution(tasks);)

But this colleague is quite "sensitive". So I need to pick my battles. So is this just a custom,meagre recreation of Task.WhenAll<TResult>?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

近箐 2025-02-19 18:01:19

不, task.whenall wheralsynchronousexecution 。这是其中的一些:

  1. task.whenall 立即实现 iEnumerable&lt; tast&lt; tresult&gt;&gt; 序列,通过枚举并将任务存储在数组中。这样可以确保所有任务都启动并运行,然后再将其连续延长。 当AllsynChronouseXecution 不执行此操作,因此根据如何实现了枚举序列,它可能会在上一个任务完成(顺序)完成后开始每个任务。
  2. task.whenall 不接受 concellationToken ,因此,完成后,您可以100%确定 all完全的。与
  3. noreferrer“> waitasync 方法( .NET >直接传播异常,作为 Innerexceptions href =“ https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.tasks.tasks.task.task.task.exception” rel =“ nofollow noreferrer”> task.exception.exception 属性。 当allsynchronousexecution 将异常包装在附加 gencregateException 中。因此,如果不重新考虑异常处理代码,则不能在两个API之间切换。
  4. task.whenall 完成为 取消 当任务都不是故障时,至少一个是取消当AllsynChronouseXecution 始终将取消作为错误传播。
  5. 当allsynchronousexecution 在其内部等待点中捕获 synchronizationContext ,因此如果呼叫者上的块。
  6. task.whenall 同步检查 null 任务实例。 当allsynchronousexecution 在等待每个任务的循环期间进行检查。

校正:实际上是集成的 concellationToken 是一个有用的功能,它已经在github上请求

Nope, there are quite a lot of differences between the Task.WhenAll and the WhenAllSynchronousExecution. Here are some of them:

  1. The Task.WhenAll materializes immediately the IEnumerable<Task<TResult>> sequence, by enumerating it and storing the tasks in an array. This ensures that all the tasks are up and running, before attaching continuations on them. The WhenAllSynchronousExecution doesn't do that, so it could potentially start each task after the completion of the previous task (sequentially), depending on how the enumerable sequence is implemented.
  2. The Task.WhenAll doesn't take a CancellationToken, so when it completes you can be 100% sure that all the tasks have completed. It is always possible to fire-and-forget a Task.WhenAll task, just like any other Task, with the WaitAsync method (.NET 6), so there is no reason to bake this functionality in every async method.
  3. The Task.WhenAll propagates the exceptions directly, as the InnerExceptions of the Task.Exception property. The WhenAllSynchronousExecution wraps the exceptions in an additional AggregateException. So you can't switch between the two APIs without rethinking your exception-handling code.
  4. The Task.WhenAll completes as Canceled when none of the tasks is Faulted, and at least one is Canceled. The WhenAllSynchronousExecution propagates the cancellation as error, always.
  5. The WhenAllSynchronousExecution captures the SynchronizationContext in its internal await points, so it might cause a deadlock if the caller blocks on async code.
  6. The Task.WhenAll checks for null task instances synchronously. The WhenAllSynchronousExecution does the check during the loop that awaits each task.

Correction: Actually the integrated CancellationToken is a useful feature, that has been requested on GitHub.

笙痞 2025-02-19 18:01:19

我认为弄清楚此方法是否存在任何理由的关键是确认在调用该方法之前是否启动任务。

  1. 如果未启动任务,则该方法可能应称为〜当alleSequention 时。
  2. 如果启动了任务,则此方法似乎不会添加任何好东西。

无论如何,我都会反对将此方法作为扩展方法:

  1. 在自动完成提示中显示此方法迟早会使某人通过已经启动任务,并认为任务将被顺序执行,但这是此方法的呼叫者任务启动时负责谁。
  2. 甚至官方时,不是扩展方法。

I think the key to figuring out if this method has any reason to exist is to confirm if the tasks are started before the method is called.

  1. If the tasks are not started then the method should probably be called ~WhenAllSequential.
  2. If the tasks are started then this method seems not to add anything good.

In any case, I would argue against having this method as an extension method:

  1. Having this method shown in auto-completion hints will sooner or later make someone pass already started tasks and think the tasks will be executed sequentially but it's the caller of this method who is in charge when the tasks are started.
  2. Even the official WhenAll is not an extension method.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文