静态构造函数中的异步任务等待行为会等待整个时间,即使任务已完成
async Task Wait behavior in static constructor waits for entire time even though task has finished
在静态构造函数中调用 Task.Run(..)..Wait(...)
时,即使任务已完成,它也会等待整个超时时间。只是好奇这是为什么?这种情况的最佳做法是什么?测试 class 如下所示
static TestClass()
{
var delay = 100;
var wait = 500;
// Will wait the whole wait time
var sw = Stopwatch.StartNew();
Task.Run(() => DoStuff(delay)).Wait(wait);
sw.Stop();
var elapsedMs = sw.ElapsedMilliseconds;
Debug.WriteLine($"Elapsed {elapsedMs}");
// Will return when task is complete
sw.Restart();
Task.Run(()=>
{
var awaiter = Task.Run(() => DoStuff(delay)).GetAwaiter();
var maxMs = delay * TimeSpan.TicksPerMillisecond;
var swElapse = Stopwatch.StartNew();
while (!awaiter.IsCompleted && swElapse.ElapsedTicks < maxMs)
{ }
swElapse.Stop();
}).Wait(wait);
sw.Stop();
elapsedMs = sw.ElapsedMilliseconds;
Debug.WriteLine($"Elapsed {elapsedMs}");
}
static void DoStuff(int delay)
{
// Some async task called and waited for result
Task.Run(async () => await Task.Delay(100)).GetAwaiter().GetResult();
}
}
var delay = 100;
var maxMs = delay * TimeSpan.TicksPerMillisecond;
var secondsTotal = maxMs / 1000.0m;
Console.WriteLine("Total seconds thread will wait: " + secondsTotal + "s.");
当您 运行 此代码时,您将获得:1000s。 1000 秒是 16.7 分钟。
您的 while 条件是:
!awaiter.IsCompleted && swElapse.ElapsedTicks < maxMs
因为这是“与”运算,只要括号中的内容为真,while 循环就会继续。
在您的情况下,“awaiter.IsCompleted”的计算结果为真,不到 16 分钟的计算结果也为真(直到 16 分钟过去)。只有当其中一个条件为假时,while 循环才会停止重复。
这可能就是您遇到此行为的原因。
in a static constructor
我上次检查时,静态构造函数锁定,因为它们一次只能执行一个。因此,如果静态构造函数排队工作到另一个线程,然后该线程执行其他操作(即调用其他静态构造函数),而原始静态构造函数在另一个线程上被阻塞,那么you can end up with a deadlock 仅在超时时解决。
What is best practice for this scenario?
Don't block on async
code,尤其是在构造函数中,尤其是 ,尤其是 ,在静态构造函数中更是如此。 (Link 是我的博客)。
在静态构造函数中调用 Task.Run(..)..Wait(...)
时,即使任务已完成,它也会等待整个超时时间。只是好奇这是为什么?这种情况的最佳做法是什么?测试 class 如下所示
static TestClass()
{
var delay = 100;
var wait = 500;
// Will wait the whole wait time
var sw = Stopwatch.StartNew();
Task.Run(() => DoStuff(delay)).Wait(wait);
sw.Stop();
var elapsedMs = sw.ElapsedMilliseconds;
Debug.WriteLine($"Elapsed {elapsedMs}");
// Will return when task is complete
sw.Restart();
Task.Run(()=>
{
var awaiter = Task.Run(() => DoStuff(delay)).GetAwaiter();
var maxMs = delay * TimeSpan.TicksPerMillisecond;
var swElapse = Stopwatch.StartNew();
while (!awaiter.IsCompleted && swElapse.ElapsedTicks < maxMs)
{ }
swElapse.Stop();
}).Wait(wait);
sw.Stop();
elapsedMs = sw.ElapsedMilliseconds;
Debug.WriteLine($"Elapsed {elapsedMs}");
}
static void DoStuff(int delay)
{
// Some async task called and waited for result
Task.Run(async () => await Task.Delay(100)).GetAwaiter().GetResult();
}
}
var delay = 100;
var maxMs = delay * TimeSpan.TicksPerMillisecond;
var secondsTotal = maxMs / 1000.0m;
Console.WriteLine("Total seconds thread will wait: " + secondsTotal + "s.");
当您 运行 此代码时,您将获得:1000s。 1000 秒是 16.7 分钟。
您的 while 条件是:
!awaiter.IsCompleted && swElapse.ElapsedTicks < maxMs
因为这是“与”运算,只要括号中的内容为真,while 循环就会继续。
在您的情况下,“awaiter.IsCompleted”的计算结果为真,不到 16 分钟的计算结果也为真(直到 16 分钟过去)。只有当其中一个条件为假时,while 循环才会停止重复。
这可能就是您遇到此行为的原因。
in a static constructor
我上次检查时,静态构造函数锁定,因为它们一次只能执行一个。因此,如果静态构造函数排队工作到另一个线程,然后该线程执行其他操作(即调用其他静态构造函数),而原始静态构造函数在另一个线程上被阻塞,那么you can end up with a deadlock 仅在超时时解决。
What is best practice for this scenario?
Don't block on async
code,尤其是在构造函数中,尤其是 ,尤其是 ,在静态构造函数中更是如此。 (Link 是我的博客)。