C# 如何等待 X 秒让任务完成
C# How to wait X seconds for a task to complete
我想在不阻塞线程的情况下等待任务完成指定的时间,并根据任务是否完成执行某些工作。
例如在特定时间内等待 HTTP 请求。
计算结束时间,然后等到那个时间过去。
public void TrySomething(int sec)
{
DateTime endTime = DateTime.Now.AddSeconds(sec);
while (DateTime.Now < endTime)
{
// do useful stuff
}
}
Stopwatch
是去这里的方法:
public void TrySomething(int sec)
{
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < (double)sec)
{
// do useful stuff
}
}
甚至:
public void TrySomething(int sec)
{
var sw = Stopwatch.StartNew();
while (true)
{
var result = ...
// do useful stuff
if (sw.Elapsed.TotalSeconds >= (double)sec)
{
return result;
}
}
}
一般情况下,您可以使用 CancellationTokenSource,如果期限已过,它会将令牌 IsCancellationRequested 属性 设置为 true。因此,您的代码将是。
public bool TrySomething(int sec)
{
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(sec)).Token;
var valueToReturne=false;
while (!ct.IsCancellationRequested)
{
if (!MyCondition)
continue;
else
valueToReturne = true;
}
return valueToReturne;
}
但是,与其他解决方案类似,这是一个繁忙的循环,意味着会阻塞您的主线程。
如果你想让你停止编程而不响应你需要让你的方法异步,例如通过将 TrySomething 包装在 Task.Run 中,例如
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(sec)).Token;
await Task.Run(() => TrySomething(ct), ct);
public bool TrySomething(CancellationToken ct)
{
var valueToReturne=false;
while (!ct.IsCancellationRequested)
{
if (!MyCondition)
continue;
else
valueToReturne = true;
}
return valueToReturne;
}
但是,这应该只用于 CPU-bound 工作。但是你说你想检查你的互联网连接,这是 IO-bound 工作。您仍然可以使用 Task.Run,但在这种情况下,这是非常不受欢迎的。最佳解决方案是使用适当的异步方法进行互联网连接检查,例如如果您使用 Ping.Send 检查互联网连接,您应该使用 Ping.SendAsync 等。
在这种情况下,您的代码将是:
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(sec)).Token;
await TrySomething(ct);
public async Task<bool> TrySomethingAsync(CancellationToken ct)
{
var valueToReturne=false;
while (!ct.IsCancellationRequested)
{
if (!await MyConditionAsync(ct))
continue;
else
valueToReturne = true;
}
return valueToReturne;
}
我想在不阻塞线程的情况下等待任务完成指定的时间,并根据任务是否完成执行某些工作。
例如在特定时间内等待 HTTP 请求。
计算结束时间,然后等到那个时间过去。
public void TrySomething(int sec)
{
DateTime endTime = DateTime.Now.AddSeconds(sec);
while (DateTime.Now < endTime)
{
// do useful stuff
}
}
Stopwatch
是去这里的方法:
public void TrySomething(int sec)
{
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < (double)sec)
{
// do useful stuff
}
}
甚至:
public void TrySomething(int sec)
{
var sw = Stopwatch.StartNew();
while (true)
{
var result = ...
// do useful stuff
if (sw.Elapsed.TotalSeconds >= (double)sec)
{
return result;
}
}
}
一般情况下,您可以使用 CancellationTokenSource,如果期限已过,它会将令牌 IsCancellationRequested 属性 设置为 true。因此,您的代码将是。
public bool TrySomething(int sec)
{
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(sec)).Token;
var valueToReturne=false;
while (!ct.IsCancellationRequested)
{
if (!MyCondition)
continue;
else
valueToReturne = true;
}
return valueToReturne;
}
但是,与其他解决方案类似,这是一个繁忙的循环,意味着会阻塞您的主线程。
如果你想让你停止编程而不响应你需要让你的方法异步,例如通过将 TrySomething 包装在 Task.Run 中,例如
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(sec)).Token;
await Task.Run(() => TrySomething(ct), ct);
public bool TrySomething(CancellationToken ct)
{
var valueToReturne=false;
while (!ct.IsCancellationRequested)
{
if (!MyCondition)
continue;
else
valueToReturne = true;
}
return valueToReturne;
}
但是,这应该只用于 CPU-bound 工作。但是你说你想检查你的互联网连接,这是 IO-bound 工作。您仍然可以使用 Task.Run,但在这种情况下,这是非常不受欢迎的。最佳解决方案是使用适当的异步方法进行互联网连接检查,例如如果您使用 Ping.Send 检查互联网连接,您应该使用 Ping.SendAsync 等。
在这种情况下,您的代码将是:
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(sec)).Token;
await TrySomething(ct);
public async Task<bool> TrySomethingAsync(CancellationToken ct)
{
var valueToReturne=false;
while (!ct.IsCancellationRequested)
{
if (!await MyConditionAsync(ct))
continue;
else
valueToReturne = true;
}
return valueToReturne;
}