【发布时间】:2017-12-07 14:15:32
【问题描述】:
为什么这段代码在 Windows 和 Linux(使用 Mono)上表现不同?
static void Main(string[] args)
{
Stopwatch stopwatch = Stopwatch.StartNew();
Task[] tasks = new Task[1];
tasks[0] = Task.Run(() =>
{
IPHostEntry iphe = Dns.GetHostEntry("8.8.8.8.dnsrbl.org");
});
Task.WaitAll(tasks, 2000);
Console.WriteLine("Done in " + stopwatch.ElapsedMilliseconds + " ms");
}
8.8.8.8.dnsrbl.ru 是一个最终会超时的查询示例。我相信没有可用的 DNS 服务器(或者它的防火墙阻止了我)。
无论如何,关键不是从 DNS 服务器获得结果,而是在等待包含对 Dns.GetHostEntry() 的调用的任务时,Task.WaitAll() 在 Windows 和 Mono 上的行为方式。
在 Windows 上,当查询在超时期限 (2 秒) 内没有返回任何结果时,程序运行大约需要 2 秒。也就是说,带有超时的 Task.WaitAll 似乎可以工作。使用 Mono 在 Linux 上运行此程序需要 2 秒才能获得输出,但程序在任务退出之前不会终止。这是为什么呢?
无论我是否使用 Time.WaitAll 超时,我似乎都获得了相同的执行时间。
线索在Dns.GetHostEntry() 中,因为如果我使用Thread.Sleep() 模拟长时间运行的任务,Task.WaitAll() 会按预期工作。
这按预期工作:
tasks[0] = Task.Run(() => Thread.Sleep(10000));
有没有办法强制Task.WaitAll(Task[] tasks, int millisecondsTimeout) 在 Mono 中运行时实际超时?
编辑:Task.WaitAll() 实际上在超时时间后返回,但在 Mono 中运行时程序不会终止(直到 Dns.GetHostEntry 超时)。
而且它不是编译器。无论是使用 Visual Studio 还是 Mono C# 编译器编译,我都会得到相同的结果。
【问题讨论】:
-
但是你说
Task.WaitAll即使在单声道上也会正确超时(你在 2 秒内得到输出,这意味着 Task.WaitAll 在 2 秒内返回)。 -
是的,我的错。对不起。该程序似乎在等待。我将编辑问题。
-
如果您删除
Task.WaitAll并在内部使用Dns.GetHostEntry开始新任务怎么办?这也会阻止程序完成吗? -
如果你开始新任务,然后输入
Thread.Sleep(2000)并退出呢? -
这意味着(很可能)Linux 上的
Dns.GetHostEntry启动了新的非后台线程。在所有非后台线程都完成之前,程序无法完成。确认这一点很难,因为单声道中的Dns.GetHostEntry最终会调用一些难以分析(甚至找不到)源代码的本机函数。
标签: c# linux multithreading dns mono