Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.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# Task.WhenAny用于非故障任务_C#_.net_Parallel Processing - Fatal编程技术网

C# Task.WhenAny用于非故障任务

C# Task.WhenAny用于非故障任务,c#,.net,parallel-processing,C#,.net,Parallel Processing,任务的描述。当任何方法说它将返回完成的第一个任务时,即使它出现故障。有没有办法改变这种行为,让它返回第一个成功的任务 像这样的东西应该可以(可能需要一些调整-尚未测试): 私有静态异步任务WaitForAnyNonFaultedTaskAsync(IEnumerable任务) { IList customTasks=tasks.ToList(); 任务完成任务; 做 { completedTask=等待任务。WhenAny(自定义任务); customTasks.Remove(completed

任务的描述。当任何
方法说它将返回完成的第一个任务时,即使它出现故障。有没有办法改变这种行为,让它返回第一个成功的任务

像这样的东西应该可以(可能需要一些调整-尚未测试):

私有静态异步任务WaitForAnyNonFaultedTaskAsync(IEnumerable任务)
{
IList customTasks=tasks.ToList();
任务完成任务;
做
{
completedTask=等待任务。WhenAny(自定义任务);
customTasks.Remove(completedTask);
}while(completedTask.IsFaulted&&customTasks.Count>0);
返回completedTask.IsFaulted?空:completedTask;
}

首先,从我的回顾来看,如果不等待所有任务完成,然后找到第一个成功运行的任务,就没有直接的方法来完成这项任务

首先,我不确定哪些边缘案例会导致我没有测试过的问题,鉴于任务和后续操作的源代码需要一个多小时的审查,我想开始考虑以下源代码。请在下面回顾我的想法

public static class TaskExtensions
{

    public static async Task<Task> WhenFirst(params Task[] tasks)
    {
        if (tasks == null)
        {
            throw new ArgumentNullException(nameof(tasks), "Must be supplied");
        }
        else if (tasks.Length == 0)
        {
            throw new ArgumentException("Must supply at least one task", nameof(tasks));
        }

        int finishedTaskIndex = -1;
        for (int i = 0, j = tasks.Length; i < j; i++)
        {
            var task = tasks[i];
            if (task == null)
                throw new ArgumentException($"Task at index {i} is null.", nameof(tasks));

            if (finishedTaskIndex == -1 && task.IsCompleted && task.Status == TaskStatus.RanToCompletion)
            {
                finishedTaskIndex = i;
            }
        }

        if (finishedTaskIndex == -1)
        {
            var promise = new TaskAwaitPromise(tasks.ToList());
            for (int i = 0, j = tasks.Length; i < j; i++)
            {
                if (finishedTaskIndex == -1)
                {
                    var taskId = i;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    //we dont want to await these tasks as we want to signal the first awaited task completed.
                    tasks[i].ContinueWith((t) =>
                    {
                        if (t.Status == TaskStatus.RanToCompletion)
                        {
                            if (finishedTaskIndex == -1)
                            {
                                finishedTaskIndex = taskId;
                                promise.InvokeCompleted(taskId);
                            }

                        }
                        else
                            promise.InvokeFailed();
                    });
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

                }

            }
            return await promise.WaitCompleted();
        }


        return Task.FromResult(finishedTaskIndex > -1 ? tasks[finishedTaskIndex] : null);
    }

    class TaskAwaitPromise
    {
        IList<Task> _tasks;
        int _taskId = -1;
        int _taskCount = 0;
        int _failedCount = 0;


        public TaskAwaitPromise(IList<Task> tasks)
        {
            _tasks = tasks;
            _taskCount = tasks.Count;
            GC.KeepAlive(_tasks);
        }

        public void InvokeFailed()
        {
            _failedCount++;
        }

        public void InvokeCompleted(int taskId)
        {
            if (_taskId < 0)
            {
                _taskId = taskId;
            }
        }

        public async Task<Task> WaitCompleted()
        {
            await Task.Delay(0);

            while (_taskId < 0 && _taskCount != _failedCount)
            {

            }
            return _taskId > 0 ? _tasks[_taskId] : null;
        }

    }

}
公共静态类任务扩展
{
开始时的公共静态异步任务(参数任务[]任务)
{
如果(任务==null)
{
抛出新ArgumentNullException(nameof(tasks),“必须提供”);
}
else if(tasks.Length==0)
{
抛出新ArgumentException(“必须提供至少一个任务”,nameof(tasks));
}
int finishedTaskIndex=-1;
for(inti=0,j=tasks.Length;i
{
if(t.Status==TaskStatus.RanToCompletion)
{
如果(finishedTaskIndex==-1)
{
FinishedTaskKindex=任务ID;
promise.InvokeCompleted(taskId);
}
}
其他的
promise.InvokeFailed();
});
#pragma warning restore CS4014//由于不等待此调用,因此在调用完成之前将继续执行当前方法
}
}
返回等待承诺。WaitCompleted();
}
返回Task.FromResult(finishedTaskIndex>-1?tasks[finishedTaskIndex]:null);
}
课堂教学承诺
{
IList_任务;
int _taskId=-1;
int _taskCount=0;
int _failedCount=0;
公共任务(IList任务)
{
_任务=任务;
_taskCount=任务。计数;
GC.KeepAlive(_任务);
}
public void InvokeFailed()
{
_失败计数++;
}
public void InvokeCompleted(int taskId)
{
如果(_taskId<0)
{
_taskId=taskId;
}
}
公共异步任务WaitCompleted()
{
等待任务。延迟(0);
而(_taskId<0&&u taskCount!=\u failedCount)
{
}
返回\u taskId>0?\u tasks[\u taskId]:空;
}
}
}
我理解代码很长,可能有很多问题,但是概念是您需要并行执行所有任务,并找到成功完成的第一个结果任务

如果我们认为需要对所有任务进行一个连续块,并且能够从延续块返回到原始调用方。我主要关心的是代码中的

while()
循环。最好添加一些CancellationToken和/或超时,以确保在等待完成任务时不会死锁。在这种情况下,如果没有任务完成,我们就永远无法完成此块

编辑
我确实稍微修改了代码,以表示承诺失败,这样我们就可以处理失败的任务。仍然对代码不满意,但这只是一个开始。

出现故障的意思是什么?不,只是自己做(在循环中调用它,直到它返回成功的任务)。我想通过使用
taskleytofault.ContinueWith(t=>t.Exception,TaskContinuationOptions.OnlyOnFaulted)可能实现这一点
在实际任务出现故障时自动触发继续任务(同时观察异常以避免同步上下文将其作为未观察到的异常重新调用)用这个作为WhenAny.Related的参数:我只是在问,但这不是在依次等待任务执行和完成,然后检查它是否成功完成,而不是并行运行它们,然后找到第一个完成的任务吗?有点像。一旦一个无故障的任务完成或所有任务都出现故障,迭代就会中断。从技术上讲,我应该更新它,如果所有的错误都返回null-可以纠正真的。如果所有任务都将出现故障-t
public static class TaskExtensions
{

    public static async Task<Task> WhenFirst(params Task[] tasks)
    {
        if (tasks == null)
        {
            throw new ArgumentNullException(nameof(tasks), "Must be supplied");
        }
        else if (tasks.Length == 0)
        {
            throw new ArgumentException("Must supply at least one task", nameof(tasks));
        }

        int finishedTaskIndex = -1;
        for (int i = 0, j = tasks.Length; i < j; i++)
        {
            var task = tasks[i];
            if (task == null)
                throw new ArgumentException($"Task at index {i} is null.", nameof(tasks));

            if (finishedTaskIndex == -1 && task.IsCompleted && task.Status == TaskStatus.RanToCompletion)
            {
                finishedTaskIndex = i;
            }
        }

        if (finishedTaskIndex == -1)
        {
            var promise = new TaskAwaitPromise(tasks.ToList());
            for (int i = 0, j = tasks.Length; i < j; i++)
            {
                if (finishedTaskIndex == -1)
                {
                    var taskId = i;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    //we dont want to await these tasks as we want to signal the first awaited task completed.
                    tasks[i].ContinueWith((t) =>
                    {
                        if (t.Status == TaskStatus.RanToCompletion)
                        {
                            if (finishedTaskIndex == -1)
                            {
                                finishedTaskIndex = taskId;
                                promise.InvokeCompleted(taskId);
                            }

                        }
                        else
                            promise.InvokeFailed();
                    });
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

                }

            }
            return await promise.WaitCompleted();
        }


        return Task.FromResult(finishedTaskIndex > -1 ? tasks[finishedTaskIndex] : null);
    }

    class TaskAwaitPromise
    {
        IList<Task> _tasks;
        int _taskId = -1;
        int _taskCount = 0;
        int _failedCount = 0;


        public TaskAwaitPromise(IList<Task> tasks)
        {
            _tasks = tasks;
            _taskCount = tasks.Count;
            GC.KeepAlive(_tasks);
        }

        public void InvokeFailed()
        {
            _failedCount++;
        }

        public void InvokeCompleted(int taskId)
        {
            if (_taskId < 0)
            {
                _taskId = taskId;
            }
        }

        public async Task<Task> WaitCompleted()
        {
            await Task.Delay(0);

            while (_taskId < 0 && _taskCount != _failedCount)
            {

            }
            return _taskId > 0 ? _tasks[_taskId] : null;
        }

    }

}