Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.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.Factory.continuewhen在任何任务毫无例外地完成时继续_C#_Async Await_Task Parallel Library_.net 4.5 - Fatal编程技术网

C# Task.Factory.continuewhen在任何任务毫无例外地完成时继续

C# Task.Factory.continuewhen在任何任务毫无例外地完成时继续,c#,async-await,task-parallel-library,.net-4.5,C#,Async Await,Task Parallel Library,.net 4.5,我的应用程序中有3个任务负责从数据库获取数据。 到现在为止,我已经一个接一个地完成了所有任务。若第一次完成并有结果,那个么这就是我的数据,若现在我开始第二个任务并再次检查 最近,我发现可以使用Task.Factory.ContinueWhenAny启动多个任务并在其中一个任务完成时继续。如果我的所有任务都没有抛出任何异常,那么这很好,但是如果任何任务失败,我就无法得到想要的结果 例如: var t1 = Task.Factory.StartNew(() => { Thread.Sl

我的应用程序中有3个任务负责从数据库获取数据。
到现在为止,我已经一个接一个地完成了所有任务。若第一次完成并有结果,那个么这就是我的数据,若现在我开始第二个任务并再次检查

最近,我发现可以使用
Task.Factory.ContinueWhenAny
启动多个任务并在其中一个任务完成时继续。如果我的所有任务都没有抛出任何异常,那么这很好,但是如果任何任务失败,我就无法得到想要的结果

例如:

var t1 = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 1;
});

var t2 = Task.Factory.StartNew(() =>
{
    Thread.Sleep(2000);
    throw new Exception("My error");
    return 2;
});

var t3 = Task.Factory.StartNew(() =>
{
    Thread.Sleep(4000);
    return 3;
});

Task.Factory.ContinueWhenAny(new[] {t1, t2,t3}, (t) =>
{
    Console.WriteLine(t.Result);
});
此代码启动3个任务并等待其中一个任务完成。 因为
t2
在2秒后抛出异常,所以无论何时
都是
continuewhen中可用的异常

从上面的代码中,我想在
t中得到3个。结果

是否有仅当任务成功完成时才继续的选项?类似于
Task.Factory.ContinueWhenAnyButSkipFailedTasks

编辑1 这是我目前基于@Nitram answer的解决方案:

var t1 = Task.Factory.StartNew(() =>
{
    var rnd = new Random();
    Thread.Sleep(rnd.Next(5,15)*1000);
    throw new Exception("My error");
    return 1;
});

var t2 = Task.Factory.StartNew(() =>
{
    Thread.Sleep(2000);
    throw new Exception("My error");
    return 2;
});

var t3 = Task.Factory.StartNew(() =>
{
    throw new Exception("My error");
    return 3;
});

var tasks = new List<Task<int>> { t1, t2, t3 };

Action<Task<int>> handler = null;

handler = t =>
{
    if (t.IsFaulted)
    {
        tasks.Remove(t);
        if (tasks.Count == 0)
        {
            throw new Exception("No data at all!");
        }
        Task.Factory.ContinueWhenAny(tasks.ToArray(), handler);
    }
    else
    {
        Console.WriteLine(t.Result);
    }
};

Task.Factory.ContinueWhenAny(tasks.ToArray(), handler);
var t1=Task.Factory.StartNew(()=>
{
var rnd=新随机数();
线程睡眠(rnd.Next(5,15)*1000);
抛出新异常(“我的错误”);
返回1;
});
var t2=Task.Factory.StartNew(()=>
{
《睡眠》(2000年);
抛出新异常(“我的错误”);
返回2;
});
var t3=Task.Factory.StartNew(()=>
{
抛出新异常(“我的错误”);
返回3;
});
var tasks=新列表{t1,t2,t3};
动作处理程序=null;
handler=t=>
{
如果(t.IsFaulted)
{
任务。删除(t);
如果(tasks.Count==0)
{
抛出新异常(“根本没有数据!”);
}
Task.Factory.ContinueWhenAny(tasks.ToArray(),handler);
}
其他的
{
控制台写入线(t.Result);
}
};
Task.Factory.ContinueWhenAny(tasks.ToArray(),handler);
我现在需要的是,当所有任务都抛出异常时,如何抛出异常?

也许可以将此方法更改为返回任务的单个方法—类似于子任务?

函数有一个重载,可以执行您想要的操作

只需将
TaskContinuationOptions
设置为
OnlyOnRanToCompletion
,失败的任务将被忽略

Task.Factory.ContinueWhenAny(new[] {t1, t2,t3}, (t) =>
{
    Console.WriteLine(t.Result);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
所以我们得出结论,这个答案实际上是错误的

从列表中删除任务似乎是我能想到的唯一方法。 我试着把它写进一些代码行中。给你:

var tasks = new List<Task> {t1, t2, t3};

Action<Task> handler = null;
handler = (Task t) =>
{
    if (t.IsFauled) {
        tasks.Remove(t);
        Task.Factory.ContinueWhenAny(tasks.ToArray, handler);
    } else {
        Console.WriteLine(t.Result);
    }
};
Task.Factory.ContinueWhenAny(tasks.ToArray, handler);
唯一的区别是外部函数需要是该函数的
async
函数。这意味着在遇到第一个
wait
时,外部函数将返回保存延续的
任务

您可以添加一个周围的函数,直到该函数完成为止。
async
-
await
模式使您能够编写“看起来”像同步代码的异步非阻塞代码


另外,我建议您使用
Task.Run
函数来生成任务,而不是
TaskFactory
。它将在以后避免一些问题。;-)

如果您使用的是.NET 4.5,您可以在任何时候使用
Task.wheny
轻松实现您想要的:

public async Task<int> GetFirstCompletedTaskAsync()
{
    var tasks = new List<Task> 
    {
        Task.Run(() =>
        {
            Thread.Sleep(5000);
            return 1;
        }),
        Task.Run(() =>
        {
            Thread.Sleep(2000);
            throw new Exception("My error");
        }),
        Task.Run(() =>
        {
            Thread.Sleep(4000);
            return 3;
        }),
    };

    while (tasks.Count > 0)
    {
        var finishedTask = await Task.WhenAny(tasks);
        if (finishedTask.Status == TaskStatus.RanToCompletion)
        {
            return finishedTask
        }

        tasks.Remove(finishedTask);
    }
    throw new WhateverException("No completed tasks");
}
公共异步任务GetFirstCompletedTaskAsync() { var tasks=新列表 { Task.Run(()=> { 睡眠(5000); 返回1; }), Task.Run(()=> { 《睡眠》(2000年); 抛出新异常(“我的错误”); }), Task.Run(()=> { 睡眠(4000); 返回3; }), }; 而(tasks.Count>0) { var finishedTask=等待任务。WhenAny(任务); if(finishedTask.Status==TaskStatus.RanToCompletion) { 返回已完成任务 } 任务。删除(完成任务); } 抛出新的WhateverException(“没有完成的任务”); }
如果只是这么做(至少对我有效):

bool taskFinishedFlag=false;
taskt1=Task.Factory.StartNew(()=>{Thread.Sleep(4000);返回1;});
taskt2=Task.Factory.StartNew(()=>{Thread.Sleep(2000);
抛出新异常(“”;返回2;});
Task t3=Task.Factory.StartNew(()=>{Thread.Sleep(4000);返回3;});
任务[]任务=新的[]{t1,t2,t3};
for(int i=0;i
{
if(taskFinishedFlag)返回;
taskFinishedFlag=true;
控制台写入线(t.Result);
},TaskContinuationOptions。无故障);
}      

谢谢您这么快的回答,但不幸的是,我得到了一个错误
将特定的延续类型排除在多个任务的延续之外是无效的。
啊。。。如果您没有正确阅读文档,就会发生这种情况。对不起,这个答案是错的。因为NotOn*和OnlyOn*选项对此函数是非法的。因为这是我唯一的想法是维护一个等待任务的列表,如果函数在失败的任务上触发,你可以删除这个,然后等待剩余的任务。你能展示一些示例代码吗?这将非常有帮助。是否有明确的理由使用此架构?或者你考虑使用异步等待模式吗?@ MISIU我给答案添加了一些代码,可以给你一个想法来解决这个问题。我在2分钟内写了这篇文章,但我对C#不是很好。因此,请在这里执行任何错误。我更喜欢VB。我认为你需要编写自己的任务。WhenAny版本需要一个Func来指定此特定任务完成是否应该完成WhenAny。我需要稍微不同的版本-我需要从所有任务中获得第一个结果,但仅从完成的任务中获得。如果他们都是错的,我想
public async Task<int> GetFirstCompletedTaskAsync()
{
    var tasks = new List<Task> 
    {
        Task.Run(() =>
        {
            Thread.Sleep(5000);
            return 1;
        }),
        Task.Run(() =>
        {
            Thread.Sleep(2000);
            throw new Exception("My error");
        }),
        Task.Run(() =>
        {
            Thread.Sleep(4000);
            return 3;
        }),
    };

    while (tasks.Count > 0)
    {
        var finishedTask = await Task.WhenAny(tasks);
        if (finishedTask.Status == TaskStatus.RanToCompletion)
        {
            return finishedTask
        }

        tasks.Remove(finishedTask);
    }
    throw new WhateverException("No completed tasks");
}
        bool taskFinishedFlag = false;

        Task t1 = Task.Factory.StartNew(() => { Thread.Sleep(4000); return 1; });

        Task t2 = Task.Factory.StartNew(() => { Thread.Sleep(2000); 
                                                throw new Exception("");return 2; });

        Task t3 = Task.Factory.StartNew(() => { Thread.Sleep(4000); return 3; });

        Task<int>[] Tasks = new[] { t1, t2, t3 };

        for (int i = 0; i < Tasks.Length; i++)
        {
            Tasks[i].ContinueWith((t) =>
                {
                    if (taskFinishedFlag) return;
                    taskFinishedFlag = true;
                    Console.WriteLine(t.Result);
                }, TaskContinuationOptions.NotOnFaulted);
        }