从异步回调调用同步方法调用?
Call Sync method call from Async Callback?
在异步回调中调用同步方法会发生什么?
示例:
private void AcceptCallback(IAsyncResult AR)
{
tcp.BeginReceive(ReceiveCallback);
}
private void ReceiveCallback(IAsyncResult AR)
{
tcp.Send(data);
}
已接受连接并启动异步接收回调。当 tcp 连接接收到数据时,它会调用 receive 回调。
如果调用同步 Send 方法,是否会阻止其他异步回调的发生?
还是所有的异步回调都是相互独立的?
是的,回调是相互独立的。它们在线程池上执行。这样做没有错。混合同步和异步 IO 很好。您可以在那些能给您带来最大好处的地方使用异步 IO(大量等待时间长的地方)。
别忘了调用 EndReceive。
另请注意,由于 await
,APM 模式已过时。也许你应该切换。
回调是独立的,因为它们是在线程池 IO 完成工作者上调用的。
如果您有兴趣,可以在 source code 中查看。此特定方法用于 Socket
class(TcpClient
和 UdpClient
在内部使用),其中重叠 IO 用于调用回调(请参阅 asyncResult.SetUnmanagedStructures
调用:
private void DoBeginReceiveFrom(byte[] buffer, int offset,
int size, SocketFlags socketFlags,
EndPoint endPointSnapshot, SocketAddress
socketAddress, OverlappedAsyncResult asyncResult)
{
EndPoint oldEndPoint = m_RightEndPoint;
SocketError errorCode = SocketError.SocketError;
try
{
// Set up asyncResult for overlapped WSARecvFrom.
// This call will use completion ports on WinNT and Overlapped IO on Win9x.
asyncResult.SetUnmanagedStructures(
buffer, offset, size,
socketAddress, true /* pin remoteEP*/,
ref Caches.ReceiveOverlappedCache);
asyncResult.SocketAddressOriginal = endPointSnapshot.Serialize();
if (m_RightEndPoint == null)
{
m_RightEndPoint = endPointSnapshot;
}
int bytesTransferred;
errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
m_Handle,
ref asyncResult.m_SingleBuffer,
1,
out bytesTransferred,
ref socketFlags,
asyncResult.GetSocketAddressPtr(),
asyncResult.GetSocketAddressSizePtr(),
asyncResult.OverlappedHandle,
IntPtr.Zero );
if (errorCode!=SocketError.Success)
{
errorCode = (SocketError)Marshal.GetLastWin32Error();
}
}
catch (ObjectDisposedException)
{
m_RightEndPoint = oldEndPoint;
throw;
}
finally
{
errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
}
}
在异步回调中调用同步方法会发生什么?
示例:
private void AcceptCallback(IAsyncResult AR)
{
tcp.BeginReceive(ReceiveCallback);
}
private void ReceiveCallback(IAsyncResult AR)
{
tcp.Send(data);
}
已接受连接并启动异步接收回调。当 tcp 连接接收到数据时,它会调用 receive 回调。
如果调用同步 Send 方法,是否会阻止其他异步回调的发生?
还是所有的异步回调都是相互独立的?
是的,回调是相互独立的。它们在线程池上执行。这样做没有错。混合同步和异步 IO 很好。您可以在那些能给您带来最大好处的地方使用异步 IO(大量等待时间长的地方)。
别忘了调用 EndReceive。
另请注意,由于 await
,APM 模式已过时。也许你应该切换。
回调是独立的,因为它们是在线程池 IO 完成工作者上调用的。
如果您有兴趣,可以在 source code 中查看。此特定方法用于 Socket
class(TcpClient
和 UdpClient
在内部使用),其中重叠 IO 用于调用回调(请参阅 asyncResult.SetUnmanagedStructures
调用:
private void DoBeginReceiveFrom(byte[] buffer, int offset,
int size, SocketFlags socketFlags,
EndPoint endPointSnapshot, SocketAddress
socketAddress, OverlappedAsyncResult asyncResult)
{
EndPoint oldEndPoint = m_RightEndPoint;
SocketError errorCode = SocketError.SocketError;
try
{
// Set up asyncResult for overlapped WSARecvFrom.
// This call will use completion ports on WinNT and Overlapped IO on Win9x.
asyncResult.SetUnmanagedStructures(
buffer, offset, size,
socketAddress, true /* pin remoteEP*/,
ref Caches.ReceiveOverlappedCache);
asyncResult.SocketAddressOriginal = endPointSnapshot.Serialize();
if (m_RightEndPoint == null)
{
m_RightEndPoint = endPointSnapshot;
}
int bytesTransferred;
errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecvFrom(
m_Handle,
ref asyncResult.m_SingleBuffer,
1,
out bytesTransferred,
ref socketFlags,
asyncResult.GetSocketAddressPtr(),
asyncResult.GetSocketAddressSizePtr(),
asyncResult.OverlappedHandle,
IntPtr.Zero );
if (errorCode!=SocketError.Success)
{
errorCode = (SocketError)Marshal.GetLastWin32Error();
}
}
catch (ObjectDisposedException)
{
m_RightEndPoint = oldEndPoint;
throw;
}
finally
{
errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
}
}