通过完成订购任务后获得对原始任务的引用? [英] Getting reference to original Task after ordering Tasks by completion?

查看:92
本文介绍了通过完成订购任务后获得对原始任务的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问前一个问题关于一种方法,该方法在完成后会命令 List< Task< T>> int 代表原始 List< Task< T>> Task 的索引c $ c>给。

I asked a question a while ago about a method that orders a List<Task<T>>> by their completion that also returns an int representing the index of the completed Task in the original List<Task<T>> given.

我暗示我可能不需要返回此 int 来确定哪个特定的 Task 已完成,我可以查询返回的 Task 以获得此信息。

I have the inkling that I might not need to return this int to determine which specific Task has completed and that I can interrogate the returned Task for this information.

作为副注,此后我更改了订购 List< Task>的方法。 。我最初使用 Task< T> ,它返回了 bool 来表示 Task< T> 是否成功完成了工作。现在,我只抛出 Exception 的子类,它提供有关 Task 失败的方式和原因的更多信息。

As a side note, I have since altered the method to order a List<Task>. I originally used Task<T>, which returned a bool to represent if the Task<T> was successful in its job or not. I now simply throw a subclass of Exception which provides more information about how and why a Task failed.

我对这个问题的想法来自以下问题:当使用此方法的 Task< int> 抛出 Exception 我无法确定哪个特定的 Task 引发了 Exception ,因为我无法查询 Task 的原始索引的 Task< int> ;.结果

My idea for this question came from the issue that when a Task<int> from this method throws an Exception I have no way to determine which specific Task threw the Exception because I cannot interrogate the Task<int>.Result for the Task's original index.

同样,如果我可以询问 Task< int> (现在只是从原始列表中引用的 Task 返回的Task ),我可以简单地比较引用。

So again, if I can interrogate the Task<int> (now simply just Task) that is returned for the Task it refers to from the original list, I can simply compare the references.

这里是现在存在的方法(此方法的原始代码,也可能是博客帖子(来自Jon Skeet)

Here is the method as it now exists (Credit to Servy for the original code for this method. Also possibly this blog post from Jon Skeet)

public static IEnumerable<Task<int>> OrderByCompletion(IEnumerable<Task> tasks)
{
    var taskList = tasks.ToList();
    var taskSources = new BlockingCollection<TaskCompletionSource<int>>();
    var taskSourceList = new List<TaskCompletionSource<int>>(taskList.Count);

    for (int i = 0; i < taskList.Count; i++)
    {
        var task = taskList[i];
        var newSource = new TaskCompletionSource<int>();
        taskSources.Add(newSource);
        taskSourceList.Add(newSource);

        int index = i;

        task.ContinueWith(t =>
        {
            var source = taskSources.Take();

            if (t.IsCanceled)
                source.TrySetCanceled();
            else if (t.IsFaulted)
                source.TrySetException(t.Exception.InnerExceptions);
            else if (t.IsCompleted)
                source.TrySetResult(index);
        }, CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
    }

    return taskSourceList.Select(tcs => tcs.Task);
}

我的第一个问题是该方法使用 TaskCompletionSource< T> 从参数列表中跟踪 Task TResult 。看到 List< Task>> 现在不返回任何值,并使用 Exception ,这是无用的,尽管它的用法这是不可避免的,因为没有非通用参数化的 TaskCompletionSource< T> ,但这并不是真正的问题,因为我可以返回一些垃圾值。

My first issue is that this method uses TaskCompletionSource<T> to track the TResult of the Task from the parameter list. Seeing as the List<Task>> now returns no value and uses Exceptions this is useless, though its usage is unavoidable because there is no non generically parameterized TaskCompletionSource<T> But this is not really a problem because I can just return some trash value.

因此,对于问题本身,我是否可以询问 Task<(未使用的返回值)> 以获得对它跟踪的 Task 的引用?

So, to the question itself, can I interrogate the Task<(unused return value)> to get a reference to the Task it tracks?

据我所知, TaskCompletionSource< T> 没有关于它正在跟踪的 Task 的信息。它只是简单地看起来像原始的 Task

From what I can tell the TaskCompletionSource<T> has no information about the Task it is tracking. It simply "looks like" the original Task.

是子类 TaskCompletionSource< T> 的唯一选项,以添加一个引用<$ c $的属性c>它跟踪的任务,在方法中设置属性的值,然后查询该属性以供参考?

Is the only option to subclass TaskCompletionSource<T> to add one property that refers to the Task it tracked, set the value of the property in the method, and then interrogate that property for the reference?

public class TaskHoldingTaskCompletionSource<T> : TaskCompletionSource<T>
{
    public Task OriginalTask { get; set; }
}


推荐答案

只是看一下方式 WhenAny 通过类似的操作解决了此问题。让该方法返回一个 Task ,其结果是 Task ,它在逻辑上表示完成,而不是计算相同逻辑价值就是那个任务。如果他们只关心任务的结果(或错误状态),这将迫使调用者解包该任务,但是如果您不总是希望将其解包,则只需返回整个 Task 。它实际上简化了代码,使它们没有 Order 方法为您解包任务。

Just look at the way WhenAny solves this problem for its analogous operation. Have the method return a Task whose result is the Task that it logically represents the completion of, rather than computing the same logical value as that task. This forces the caller to unwrap that task if they just care about the task's result (or error state), but if you don't always want it unwrapped, you can just return the whole Task. It actually simplifies the code to not have the Order method unwrap the task for you.

public static IEnumerable<Task<Task>> Order2(this IEnumerable<Task> tasks)
{
    var taskList = tasks.ToList();

    var taskSources = new BlockingCollection<TaskCompletionSource<Task>>();

    var taskSourceList = new List<TaskCompletionSource<Task>>(taskList.Count);
    foreach (var task in taskList)
    {
        var newSource = new TaskCompletionSource<Task>();
        taskSources.Add(newSource);
        taskSourceList.Add(newSource);

        task.ContinueWith(t => taskSources.Take().TrySetResult(t),
            CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
    }

    return taskSourceList.Select(tcs => tcs.Task);
}

这篇关于通过完成订购任务后获得对原始任务的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆