【问题标题】:async method not blocking on desktop but blocking on server?异步方法不在桌面上阻塞但在服务器上阻塞?
【发布时间】:2012-07-16 21:47:55
【问题描述】:

我做了一个简单的异步方法来异步调用 SQL 存储过程。

在我的控制台程序中,我在循环中调用此方法 1000 次,并在每次调用之间休眠 1ms (Thread.Sleep)。 我在进入循环之前启动一个秒表,退出循环时停止它,并显示在循环中花费的时间。

在我的开发机器(Win7 - VS 2012 RC)上,我可以看到我期望看到的内容:

Completed in 1006 ms

考虑到对 async 方法的调用几乎立即返回(当到达第一个 await 关键字时),这似乎是合乎逻辑的,因此在等待之前执行代码时只会产生少量开销(6 毫秒)。

但是,当我在安装了 .NET Framework 4.5 RC 的服务器计算机 (Win2008 R2 SP1) 上运行完全相同的代码时,代码运行良好,但执行时间与我预期的相差甚远,在没有与在我的开发机器上运行程序时获得的比较:

Completed in 15520 ms

意味着被调用的异步方法并没有真正异步调用,第一个等待似乎以某种方式阻塞?

这是我正在调用的异步方法的代码:

public async void CallSpAsync()
{
  var cmd = new SqlCommand("sp_mysp");
  {  
     var conn = new SqlConnection(connectionString);
     {
       cmd.Connection = conn;
       cmd.CommandType = CommandType.StoredProcedure;

       [...Filling command parameters here - nothing interesting...]

       await cmd.Connection.OpenAsync();                    
       await cmd.ExecuteNonQueryAsync();

       cmd.Dispose();
       cmd.Connection.Dispose();
     }
  }
}

这里是主程序测试代码(循环):

Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
   CallSpAsync();
   Thread.Sleep(1);
}
sw.Stop();

我在两台机器上运行完全相同的可执行文件(在 Release 中编译的控制台程序)。

我很想弄清楚为什么在服务器机器上运行程序时没有真正异步调用该方法。

有什么想法吗?

谢谢!

编辑

该问题与运行正常的 async/await 无关,而是由于服务器上的计时器分辨率(由 StopWatch 使用)比我的工作站上的时间少 15 倍。代码并没有运行得更慢,只是计时器的分辨率导致了不正确的经过时间计算。

请参阅下面 James Manning 的回答。

【问题讨论】:

  • 您在这两种情况下都在运行控制台程序?
  • 尝试在调试器中中断几次,看看它在您的服务器计算机上停止的位置。
  • 部分异步方法仍然同步运行(尤其是 DNS 查找)。
  • @usr :在没有附加调试器的情况下,我确实在运行相同的控制台程序(在 Release 中编译)。不幸的是,服务器机器没有配置为允许远程调试,如果没有人知道,我会在万不得已的情况下这样做;)
  • @SLaks :确实,但这不是这里的问题。问题是,在我的桌面开发机器上,该方法是完全异步运行的,而在服务器机器上,该方法是同步(或部分异步)运行的。

标签: c# .net async-await


【解决方案1】:

这可能是服务器机器上计时器分辨率的函数。检查 ClockRes 实用程序。您可以在my comment on High accuracy DateTime.UtcNow获取更多详细信息。

【讨论】:

  • 看起来确实如此!在我的工作站上运行 clockres 实用程序给了我 15.600/0.500/1.000 (ms) 的最大/最小/电流。在服务器上运行 clockres 实用程序给了我 15.625/0.500/15.625 (ms) 的最大/最小/电流。什么……?所以确实是这个问题。非常感谢您的回答,我本来可以转几个小时的。所以它与 async/await 无关,这并不意味着代码运行速度较慢,只是计时器分辨率不正确。有没有办法解决这个问题?
  • @Stephen :是的,但它是为了特定基准演示的目的而存在的。有什么方法可以更改服务器上的计时器分辨率?
  • @darkey:据我所知没有。微睡眠并不是那么便携。您究竟想在演示中展示什么?
  • @Stephen :经过一番思考,我确实可以在实现相同演示的同时摆脱 Thread.Sleep(1) 。这是一个愚蠢的想法,但至少它让我发现了一些关于计时器分辨率的新东西;)谢谢
  • @darkey:经过更多研究,结果证明you can change the system timer resolution(通过 P/调用未记录的函数)。我仍然不推荐它,尤其是在服务器上。 :)
猜你喜欢
  • 1970-01-01
  • 2018-04-06
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多