gpt4 book ai didi

.net - 创建具有超时的任务

转载 作者:行者123 更新时间:2023-12-01 12:45:15 24 4
gpt4 key购买 nike

我希望执行一系列任务,每个任务都有自己的超时时间。

我从这里借用了创建超时任务的扩展方法
http://blogs.msdn.com/b/pfxteam/archive/2011/11/10/10235834.aspx

所以代码如下

 public static Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
// Short-circuit #1: infinite timeout or task already completed
if (task.IsCompleted || (millisecondsTimeout == Timeout.Infinite))
{
// Either the task has already completed or timeout will never occur.
// No proxy necessary.
return task;
}

// tcs.Task will be returned as a proxy to the caller
TaskCompletionSource<VoidTypeStruct> tcs = new TaskCompletionSource<VoidTypeStruct>();

// Short-circuit #2: zero timeout
if (millisecondsTimeout == 0)
{
// We've already timed out.
tcs.SetException(new TimeoutException());
return tcs.Task;
}

// Set up a timer to complete after the specified timeout period
Timer timer = new Timer(state =>
{
// Recover your state information
var myTcs = (TaskCompletionSource<VoidTypeStruct>)state;
// Fault our proxy with a TimeoutException
myTcs.TrySetException(new TimeoutException());
}, tcs, millisecondsTimeout, Timeout.Infinite);

// Wire up the logic for what happens when source task completes
task.ContinueWith(antecedent =>
{
timer.Dispose(); // Cancel the timer
MarshalTaskResults(antecedent, tcs); // Marshal results to proxy
},
CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

return tcs.Task;
}

public class Program
{
private static List<int> Output = new List<int>();

private static Random _random = new Random();
public static void LongRunningTask(string message)
{
Console.WriteLine(message);
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
//Simulate a long running task
Thread.Sleep(TimeSpan.FromSeconds(3));
var number = _random.Next();
Console.WriteLine("Adding " + number);
Output.Add(number);
}
public static void Main(string[] args)
{
var tasks = new List<Task>();

var t1 = Task.Factory.StartNew(_ => LongRunningTask("Entering task1"),TaskCreationOptions.AttachedToParent).TimeoutAfter(10);
var t2 = Task.Factory.StartNew(_ => LongRunningTask("Entering task2"),TaskCreationOptions.AttachedToParent);
var t3 = Task.Factory.StartNew(_ => LongRunningTask("Entering task3"),TaskCreationOptions.AttachedToParent);

tasks.Add(t1);
tasks.Add(t2);
tasks.Add(t3);

try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
Console.WriteLine("There was an exception");
Console.WriteLine(ex.InnerException.Message);
}

Console.WriteLine("Output :");
Output.ForEach(_ => Console.WriteLine(_));

Console.ReadLine();
}
}



the output

Entering task1
Managed thread Id 10
Entering task2
Managed thread Id 11
Entering task3
Managed thread Id 14
Adding 453738994
Adding 156432981
Adding 1340619865
There was an exception
The operation has timed out.
Output :
453738994
156432981
1340619865

现在,我无法理解的是为什么即使我指定了超时并且发生了超时异常,t1 仍然完成。

我正在使用.net 4。

编辑 :

确保超时任务在超时期限后不做任何事情,即完全取消任务。
public class Program
{
private static List<int> Output = new List<int>();

private static Random _random = new Random();
public static int LongRunningTask(string message)
{
Console.WriteLine(message);
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
//Simulate a long running task
Thread.Sleep(TimeSpan.FromSeconds(2));
var number = _random.Next();
Console.WriteLine("Adding " + number + " From thread - " + Thread.CurrentThread.ManagedThreadId);
return number;
}
public static void Main(string[] args)
{
Console.WriteLine("In Main");
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
var cts = new CancellationTokenSource();
var tasks = new List<Task>();

var t1 = Task.Factory.StartNew(_ => LongRunningTask("Entering task1"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result),cts.Token)
.TimeoutAfter(1000);
var t2 = Task.Factory.StartNew(_ => LongRunningTask("Entering task2"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result));
var t3 = Task.Factory.StartNew(_ => LongRunningTask("Entering task3"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result));

tasks.Add(t1);
tasks.Add(t2);
tasks.Add(t3);

try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
Console.WriteLine("There was an exception");
Console.WriteLine(ex.InnerException.Message);
cts.Cancel();
}

Console.WriteLine("Output :");
Output.ForEach(_ => Console.WriteLine(_));

Console.ReadLine();
}
}

输出 :
In Main
Managed thread Id 9
Entering task1
Managed thread Id 10
Entering task2
Managed thread Id 11
Entering task3
Managed thread Id 13
Adding 1141027730 From thread - 10
Adding 1856518562 From thread - 13
Adding 1856518562 From thread - 11
There was an exception
The operation has timed out.
Output :
1141027730
1856518562
1856518562

最佳答案

输出包含三个值,因为程序等待所有任务 Task.WaitAll(tasks.ToArray());并且输出是公共(public)领域(因为闭包)

你可以只保留第一个任务,你会看到另一个结果

Entering task1
Managed thread Id 10
There was an exception
The operation has timed out.
Output :
Adding 1923041190
Managed thread Id 10

请注意, Adding已调用,但 Output 中没有该号码. Adding被调用是因为 LongRunningTask在此任务中工作 Task.Factory.StartNew(_ => LongRunningTask("Entering task1"), TaskCreationOptions.AttachedToParent)并且在不同的线程上引发了异常。此异常不会影响 LongRunningTask
编辑:

有几种选择:
  • 调用 t1.Wait异常会立即重新抛出,你可以取消任务
  • 调用 TimeoutAfter(10)在继续之前
        var t1 = Task.Factory.StartNew(() => LongRunningTask("Entering task1"))
    .TimeoutAfter(10)
    .ContinueWith(_=> Output.Add(_.Result), cts.Token);
  • Continue完成后才会执行 TimeoutAfterLongRunningTask ,但您必须更新 TimeoutAfter , 你必须返回 Task<Result>不是 Task
        public static Task<Result> TimeoutAfter<Result>(this Task<Result> task, int millisecondsTimeout)
    {
    // Short-circuit #1: infinite timeout or task already completed
    if (task.IsCompleted || (millisecondsTimeout == Timeout.Infinite))
    {
    Console.WriteLine("task.IsCompleted");
    // Either the task has already completed or timeout will never occur.
    // No proxy necessary.
    return task;
    }
    // tcs.Task will be returned as a proxy to the caller
    var tcs = new TaskCompletionSource<Result>();

    // Short-circuit #2: zero timeout
    if (millisecondsTimeout == 0)
    {
    // Console.WriteLine("millisecondsTimeout == 0");
    // We've already timed out.
    tcs.SetException(new TimeoutException());
    return tcs.Task;
    }

    // Set up a timer to complete after the specified timeout period
    var timer = new Timer(state => tcs.TrySetException(new TimeoutException()), null, millisecondsTimeout, Timeout.Infinite);

    // Wire up the logic for what happens when source task completes
    task.ContinueWith(antecedent =>
    {
    timer.Dispose();
    MarshalTaskResults(antecedent, tcs);
    }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

    return tcs.Task;
    }

    关于.net - 创建具有超时的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20717414/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com