Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 按完成时间排序任务,同时在参数列表中跟踪其索引?_C#_Task Parallel Library_Ienumerable - Fatal编程技术网

C# 按完成时间排序任务,同时在参数列表中跟踪其索引?

C# 按完成时间排序任务,同时在参数列表中跟踪其索引?,c#,task-parallel-library,ienumerable,C#,Task Parallel Library,Ienumerable,我最近讨论了清理某些代码的可能性,该代码意味着等待列表中的每个任务完成,但如果返回了一些错误值,则取消所有任务 一个名为Servy的用户,它雄辩地按完成时间排序一个列表。把答案读了一遍后,我想我理解了这个方法。然后我开始使用这种方法,但很快就意识到了一个问题。我需要能够在任务完成时识别任务。但是Servy建议的Order方法无法实现这一点(因为我无法将Order返回的任务延续与我最初提供的列表进行比较) 因此我改变了方法,返回一个Tuple,其中int表示所提供参数中任务的原始索引 public

我最近讨论了清理某些代码的可能性,该代码意味着等待
列表中的每个
任务
完成,但如果返回了一些错误值,则取消所有
任务

一个名为Servy的用户,它雄辩地按完成时间排序一个
列表。把答案读了一遍后,我想我理解了这个方法。然后我开始使用这种方法,但很快就意识到了一个问题。我需要能够在任务完成时识别任务。但是Servy建议的
Order
方法无法实现这一点(因为我无法将
Order
返回的任务延续与我最初提供的
列表进行比较)

因此我改变了方法,返回一个
Tuple
,其中
int
表示所提供参数中
任务的原始索引

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;
公共静态IEnumerable OrderByCompletion(IEnumerable任务)
{
var taskList=tasks.ToList();
var taskSources=new BlockingCollection();
var taskSourceList=新列表(taskList.Count);
for(int i=0;i
{
var source=taskSources.Take();
如果(t.IsCanceled)
source.TrySetCanceled();
否则,如果(t.IsFaulted)
source.TrySetException(t.Exception.InnerExceptions);
否则,如果(t.已完成)
TrySetResult(新元组(t.Result,i));
},CancellationToken.None,TaskContinuationOptions.PreferFairity,TaskScheduler.Default);
}
返回taskSourceList.Select(tcs=>tcs.Task);
}
//用法
foreach(myTaskList.OrderByCompletion()中的var任务)
元组结果=等待任务;
我面临的问题是,返回的
元组中的索引似乎总是等于传递给
OrderByCompletion
的原始
列表的
Count
,而不管返回任务的顺序如何

我认为,由于这个问题,我并不完全理解这个方法最初是如何工作的,尽管它似乎应该工作得很好


有人能解释问题并提供解决方案吗?

发生这种情况是因为您在
操作中使用了
i
变量

但是,在创建
操作时不会执行此操作的代码,而是在任务完成时,变量
i
具有值
taskList.Count
(当
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);
}
for(int i=0;i

有关更多详细信息,请阅读本节。

发生这种情况是因为您在
操作中使用了
i
变量

但是,在创建
操作时不会执行此操作的代码,而是在任务完成时,变量
i
具有值
taskList.Count
(当
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);
}
for(int i=0;i

您可以阅读此文了解更多详细信息。

Ohhhhhhh耶!我以前在一篇博客文章中看到过这个“问题”(我想是Eric Lippert?)。这完全有道理。非常感谢。哦,是的!我以前在一篇博客文章中看到过这个“问题”(我想是Eric Lippert?)。这完全有道理。非常感谢。