gpt4 book ai didi

c# - 如何在 C# 中为计时器实现任务异步?

转载 作者:太空狗 更新时间:2023-10-29 18:16:10 25 4
gpt4 key购买 nike

我希望给定的操作执行一定的时间。当该时间到期时,发送另一个执行命令。

StartDoingStuff();
System.Threading.Thread.Sleep(200);
StopDoingStuff();

我如何在 C# 中使用 Async/Task/Await 来编写它,而不是在其中使用阻塞应用程序其余部分的 sleep 语句?

最佳答案

Joe Hoag 于 2011 年在 Parallel Team 的博客中回答了这个问题:Crafting a Task.TimeoutAfter Method .

该解决方案使用 TaskCompletionSource 并包括多项优化(12% 仅通过避免捕获)、处理清理并涵盖边缘情况,例如在目标任务已经完成时调用 TimeoutAfter、传递无效超时等。

Task.TimeoutAfter 的美妙之处在于它很容易与其他延续组合在一起,因为它只做一件事:通知您超时已过期。它不会尝试取消您的任务。当抛出 TimeoutException 时,您可以决定要做什么。

还介绍了 Stephen Toub 使用 async/await 的快速实现,但也没有涵盖边缘情况。

优化后的实现是:

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, state) =>
{
// Recover our state data
var tuple =
(Tuple<Timer, TaskCompletionSource<VoidTypeStruct>>)state;

// Cancel the Timer
tuple.Item1.Dispose();

// Marshal results to proxy
MarshalTaskResults(antecedent, tuple.Item2);
},
Tuple.Create(timer, tcs),
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);

return tcs.Task;
}

和 Stephen Toub 的实现,没有检查边缘情况:

public static async Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
await task;
else
throw new TimeoutException();
}

关于c# - 如何在 C# 中为计时器实现任务异步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18646650/

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