按完成时间排序任务,同时在参数列表中跟踪其索引? [英] Ordering Tasks by completion time while keeping track of their index in an argument list?

查看:206
本文介绍了按完成时间排序任务,同时在参数列表中跟踪其索引?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近

I recently asked a question about the possibility of cleaning up some code, the code was meant to wait for each Task in a List<Task<T>> to complete but cancelling all Task if one returned some falsey value.

名为Servy的用户迅速生成了一种方法,雄辩地在完成时间之前订购了List<Task<T>>.阅读答案后,我认为/认为我理解/理解了该方法.然后,我去使用该方法,但很快意识到了一个问题.我需要能够在Task完成时识别它们.但是Servy建议的Order方法没有提供执行此操作的方法(因为我无法将Order返回的任务继续与我最初提供的List<Task<>>进行比较).

A user named Servy quickly produced a method which eloquently orders a List<Task<T>> by their completion time. After reading over the answer a bit I think/thought I understand/stood the method. I then went to use the method but quickly realized an issue. I need to be able to recognize the Tasks as they are completing. But the Order method Servy suggested provides no means to do this (because I cannot compare the task continuations returned by Order to my List<Task<>> I supplied it originally).

因此,我去更改了方法以返回Tuple<T, int>,其中int表示提供的参数中Task的原始索引.

So I went to change the method to return a Tuple<T, int> where the int represents the original index of the Task in the provided arguments.

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

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

        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(new Tuple<T, int>(t.Result, i));
        }, CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
    }

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

// Usage
foreach(var task in myTaskList.OrderByCompletion())
    Tuple<Boolean, int> result = await task;

我面临的问题是,无论返回的任务顺序如何,返回的Tuple内部的索引似乎总是等于传递给OrderByCompletion的原始List<Task<>>Count.

The issue I am facing is that index inside of the Tuple returned seems to always be equal to the Count of the original List<Task<>> passed to OrderByCompletion no matter the order of the task returned.

我认为,由于这个问题,我似乎并不完全了解此方法的工作原理,尽管似乎应该可以正常工作.

I assume that as a result of this issue I do not fully understand how this method worked in the first place, though it seems to be that it should work just fine.

任何人都可以解释该问题并提供解决方案吗?

推荐答案

之所以会发生这种情况,是因为您在Action<>中使用了i变量.

This happens because you are using i variable inside an Action<>.

但是创建Action时不会执行此操作的代码,但是当任务完成时,变量i的值为taskList.Count(for循环完成时).

But the code of this action is not executed when your create the Action, but when the task is completed, then the variable i has value taskList.Count (when for loop finished).

您只需将一个额外的变量添加到for即可解决您的问题:

You can fix your problem simply adding an extra variable to the for:

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

    int index = i; // <- add this variable.

    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(new Tuple<T, int>(t.Result, index));
    }, CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
}

您可以阅读此问题/答案以了解更多详细信息.

You can read this question/answers for more details.

这篇关于按完成时间排序任务,同时在参数列表中跟踪其索引?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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