C# 异步方法在桌面上不阻塞,但在服务器上阻塞?

C# 异步方法在桌面上不阻塞,但在服务器上阻塞?,c#,.net,async-await,C#,.net,Async Await,我创建了一个简单的异步方法来异步调用SQL存储过程 在我的控制台程序中,我在一个循环中调用这个方法1000次,每次调用之间睡眠1ms(Thread.sleep)。 我在进入环路之前启动秒表,在退出环路时停止,并显示在环路中花费的时间 在我的开发机器(Win7-VS 2012 RC)上,我可以看到我期望看到的: Completed in 1006 ms 考虑到异步方法的调用几乎立即返回(当到达第一个await关键字时),这似乎是合乎逻辑的,因此在await之前执行代码时只会产生少量开销(6ms)

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

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

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

Completed in 1006 ms
考虑到异步方法的调用几乎立即返回(当到达第一个
await
关键字时),这似乎是合乎逻辑的,因此在await之前执行代码时只会产生少量开销(6ms)

但是,当我在安装了.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=新秒表();
sw.Start();
对于(int i=0;i<1000;i++)
{
CallSpAsync();
睡眠(1);
}
sw.Stop();
我在两台机器上运行完全相同的可执行文件(在发行版中编译的控制台程序)

我想弄明白为什么在服务器机器上运行程序时,该方法不能真正异步调用

有什么想法吗

谢谢

编辑

问题与async/await无关,async/await工作正常,但原因是服务器上的计时器分辨率(StopWatch使用)比我的工作站上的计时器分辨率低15倍。代码的运行速度一点也不慢,只是计时器的分辨率导致了不正确的运行时间计算


请参阅下面James Manning的答案。

这可能是服务器上计时器分辨率的函数。检查ClockRes实用程序。您可以在中获得更多详细信息。

您在这两种情况下都在运行控制台程序?请尝试中断调试器几次,看看它在您的服务器计算机上停止的位置。某些异步方法的部分仍然同步运行(尤其是DNS查找)。@usr:我确实在运行相同的控制台程序(在发行版中编译)在这两种情况下,都没有附加调试程序。不幸的是,服务器机器没有配置为允许远程调试,如果没有人知道的话,我将在最后的手段中执行此操作;)@SLaks:的确,但这不是问题所在。问题是,在我的桌面开发机器上,该方法是完全异步运行的,而在服务器机器上,该方法是同步(或部分异步)运行的。看起来确实如此!在我的工作站上运行clockres实用程序时,我的最大/最小/电流为15.600/0.500/1.000(ms)。在服务器上运行clockres实用程序时,我的最大/最小/电流为15.625/0.500/15.625(ms)。什么?因此,这确实是一个问题。非常感谢你的回答,我本来可以绕圈子转几个小时的。因此,它与async/await无关,这并不意味着代码运行较慢,只是计时器分辨率不正确。有没有办法解决这个问题?@Stephen:是的,但它是为了特定的基准测试演示而存在的。有没有办法改变服务器上的计时器分辨率?@Darky:据我所知,没有。微睡眠并不是那么方便携带。斯蒂芬:经过一番思考后,我确实可以摆脱这个线程。在完成同样的演示时,睡觉(1)。这是一个愚蠢的想法,但至少它让我发现了一些关于计时器分辨率的新东西;)Thanks@darkey:经过进一步研究,结果是(通过调用未记录的函数)。但我还是不推荐它,尤其是在服务器上。:)
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
   CallSpAsync();
   Thread.Sleep(1);
}
sw.Stop();