为什么TcpClient.Connect即使同步运行,也不会在异步方法中抛出异常
本文关键字:异步方法 抛出异常 Connect TcpClient 运行 同步 为什么 | 更新日期: 2023-09-27 18:01:36
- 为什么即使没有指定等待,此代码也不会引发System.Net.Sockets.SocketException?(没有服务器在指定端口侦听(
-
Why Thread.Sleep(4000(;不执行?
public class AsyncTcpClientDemos { private static readonly ILog Logger = LogProvider.GetCurrentClassLogger(); public async Task ConnectTcpClientNoException() { Logger.Debug("ConnectTcpClientNoException() - start"); var tcp = new TcpClient(); tcp.Connect("127.0.0.1", 9045); Thread.Sleep(4000); } }
方法是从NUnit测试中调用的:
[Test]
public void AsyncTcpClientNoExceptionTest()
{
var asyncAwait = new AsyncTcpClientDemos();
// TODO: find out why this is not throwing exception
asyncAwait.ConnectTcpClientNoException();
}
async
方法从不直接抛出异常。相反,如果在方法体中引发异常,则异步方法返回的任务将出现故障。
睡眠没有被执行,因为异常确实阻止了方法的其余部分的执行——只是异常通过Task
传播,而不是直接向上传播到堆栈。
如果您真的希望方法的第一部分抛出异常,可以将其一分为二。例如:
public Task FooAsync(int x, int y)
{
if (x < y)
{
// This will be thrown straight to the caller, in the
// normal way
throw new ArgumentException("...");
}
return FooAsyncImpl(x, y);
}
private async Task FooAsyncImpl(int x, int y)
{
// Any exceptions thrown here will be propagated via the task
}
为什么此代码甚至没有抛出System.Net.Sockets.SocketException如果没有指定等待?
正因为如此。您没有在等待返回的任务。如果你在等待,你会看到异常传播:
[Test]
public async Task AsyncTcpClientNoExceptionTest()
{
var asyncAwait = new AsyncTcpClientDemos();
await asyncAwait.ConnectTcpClientNoException();
}
即使通过同步阻止,你也可以看到(正如@Luan所建议的((只是为了表明这一点,实际上不要使用这个(:
[Test]
public void AsyncTcpClientNoExceptionTest()
{
var asyncAwait = new AsyncTcpClientDemos();
asyncAwait.ConnectTcpClientNoException().GetAwaiter().GetResult();
}
当您使用async void
时,您将强制执行"fire-and-forget"风格,即完全放弃出现故障的任务。这恰好产生了吞咽异常的不希望的行为。如果您注册TaskScheduler.UnobservedTaskException
,您将能够看到当任务完成时,会触发此事件。
Why Thread.Sleep(4000(;不执行?
正如John所说,因为异常确实发生了,所以它根本没有反映在您编写的代码中。将任务的执行更改为正确等待将显示这一点。