C# 存在队列和超时问题的TaskScheduler

C# 存在队列和超时问题的TaskScheduler,c#,multithreading,task-parallel-library,taskscheduler,C#,Multithreading,Task Parallel Library,Taskscheduler,我试图实现的目标是: 任务调度器,使任务排队并并行运行指定数量的任务,而其他任务在队列中等待开始。每个任务都有超时,当任务运行时开始计数,如果超过该时间,则取消任务并抛出TimeoutException,该异常将在ContinueWith(或紧接其后运行的某个任务)中处理。任务应由用户取消 我得到的是: 当第一个任务失败时,所有其他任务都会立即失败 以下是我的任务计划程序的完整代码(摘自MSDN,经过一些修改): 。(有关功能位于第161行) 以下是示例用法: var taskTokens =

我试图实现的目标是:

任务调度器,使任务排队并并行运行指定数量的任务,而其他任务在队列中等待开始。每个任务都有超时,当任务运行时开始计数,如果超过该时间,则取消任务并抛出TimeoutException,该异常将在ContinueWith(或紧接其后运行的某个任务)中处理。任务应由用户取消

我得到的是:

当第一个任务失败时,所有其他任务都会立即失败

以下是我的任务计划程序的完整代码(摘自MSDN,经过一些修改):

。(有关功能位于第161行)

以下是示例用法:

var taskTokens = new List<CancellationToken>();
var factory = new TaskScheduleFactory(new ParallelOptions() { MaxDegreeOfParallelism = 1 }); //for the purpose of testing, supposed to work and with higher values
for (var i = 0; i < 10; i++)
{
    //TaskScheduleFactory.cs, line 161
    var taskToken = factory.Add(
        (token) => //Task
        {
            Console.WriteLine("Start");
            Thread.Sleep(5000);
            if (token.IsCancellationRequested) return; //Cancelled by timeout
            Console.WriteLine("This should not print");
        },
        (task) => //ContinueWith
        {
            if (task.IsFaulted)
            {
                Console.WriteLine("Fail");
            }
            else if (!task.IsCompleted)
            {
                Console.WriteLine("Not completed");
            }
            else Console.WriteLine("Done");
        },
        2000 //Timeout
    );
    taskTokens.Add(taskToken);
}
对于MaxDegreeOfParallelism=2:

Start;
Start;
(Wait 2sec)
Fail;
Fail;
Start;
Start;
(Wait 2sec)
Fail;
Fail;
....
工作原理:

Start;
(Wait 2sec)
Fail;
Fail;
Fail;
Fail;
...
(对于MaxDegreeOfParallelism=1,其余的也都是混乱的)


注意:这是我使用TPL的第一步,请原谅我方在
Add
中的任何愚蠢行为。这意味着一旦创建任务,超时就会开始。我认为您的意图是在任务开始执行时才开始超时


由于第一个任务比超时时间长,因此所有其他任务在轮到它们时都已超时。

这不是完美的解决方案,但却是我能想到的最佳解决方案:

public CancellationTokenSource Add(Action<CancellationToken> action, Action<Task> callback, int timeoutInMilliseconds)
{
    var cts = new CancellationTokenSource();
    Instance.StartNew(() =>
    {
        cts.CancelAfter(timeoutInMilliseconds);
        var task = Task.Factory.StartNew(() => action(cts.Token), cts.Token, TaskCreationOptions.AttachedToParent|TaskCreationOptions.LongRunning, TaskScheduler.Default);
        try
        {
            task.Wait(timeoutInMilliseconds, cts.Token);
        }
        catch (OperationCanceledException) { }
        callback(task);
    }, cts.Token);
    return cts;
}
public CancellationTokenSource添加(操作操作、操作回调、int timeoutin毫秒)
{
var cts=新的CancellationTokenSource();
Instance.StartNew(()=>
{
cts.CancelAfter(timeoutin毫秒);
var task=task.Factory.StartNew(()=>action(cts.Token)、cts.Token、TaskCreationOptions.AttachedToParent | TaskCreationOptions.longlunning、TaskScheduler.Default);
尝试
{
task.Wait(timeoutin毫秒,cts.Token);
}
捕获(操作取消异常){}
回调(任务);
},cts.Token);
返回cts;
}

简言之:当任务从队列启动时,它会在默认的任务调度程序上创建子任务(因为另一个任务只是将其排队),然后我们等待一定的时间并调用回调函数。不知道这有多糟。

好的观点。我离开了一段时间,继续进入行动的身体,但仍然努力使它正常工作。你能详细说明一下如何修复它吗?你已经在那里写了一些非常高级的代码。我认为您可以解决:)类似的问题:
var-workTask=Instance.StartNew(()=>{cts.CancelAfter(timeoutinmillizes);action(cts.Token);},cts.Token);var resultTask=Task.WhenAll(工作任务,cts.Token)。这可能会在您不喜欢的状态下完成
resultTask
(我想它最终会被取消)。如果您想要更多的控制,您可以通过
TaskCompletionSource
实现任何完成行为。呵呵,我前面提到过,我从MSDN示例中复制了该主题的大部分代码。我写的唯一部分是一个实际上不起作用的部分。谢谢你的帮助!我将离开几天,因此需要一些时间来验证它并将其标记为答案(除非我的愚蠢妨碍了我正确实施它)。干杯,祝你一周愉快!有点不对劲。对于初学者,Task.WhenAll不接受CancellationToksn作为第二个参数。我看不出还有什么。抱歉这么无礼…好吧,我对第三方物流的这一领域不是100%熟悉。这看起来不错:
public CancellationTokenSource Add(Action<CancellationToken> action, Action<Task> callback, int timeoutInMilliseconds)
{
    var cts = new CancellationTokenSource();
    Instance.StartNew(() =>
    {
        cts.CancelAfter(timeoutInMilliseconds);
        var task = Task.Factory.StartNew(() => action(cts.Token), cts.Token, TaskCreationOptions.AttachedToParent|TaskCreationOptions.LongRunning, TaskScheduler.Default);
        try
        {
            task.Wait(timeoutInMilliseconds, cts.Token);
        }
        catch (OperationCanceledException) { }
        callback(task);
    }, cts.Token);
    return cts;
}