我有一个在启动时加载管理数据的应用程序 (.NET 4.0)。我必须进行 25 个并发异步 WCF 调用,其中一些很快(40 毫秒),另一些则需要更长的时间来执行,最多 882 毫秒。我计划将数据存储在本地,但是对于第一次应用程序启动,它需要尽快完成。
应该注意的是,代理位于针对 .NET 3.5 的库中,并且在 Jeffrey Richter 的 Async Enumerator 的帮助下,在内部使用封装到异步方法中的 BeginXxx 和 EndXxx 方法模式。
将使用的每个客户端代理的 WCF 通道工厂在启动调用之前打开。
目前,我正在使用 Task.Factory.StartNew 和启动每个异步调用的操作。经验如下:
- 所有 BeginXXX 呼叫都已发送。
- 该程序似乎在我的代码之外运行了至少 10 秒。
- 最后发送所有 EndXXX 调用以检索结果。
我想知道为什么会出现这样的延迟。我的电脑有4核,如果并发调用数限制为4,根本没有延迟,只要我添加另一个调用,就会出现延迟。
任何帮助表示赞赏。
编辑 1:使用的绑定是 netTcpBinding。
服务器配置如下:
<netTcpBinding>
<binding transactionFlow="true" listenBacklog="500" maxReceivedMessageSize="400000"
portSharingEnabled="false">
<readerQuotas maxDepth="200" />
<reliableSession enabled="false" />
<security mode="None">
<transport clientCredentialType="None" protectionLevel="None" />
<message clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
<service name="AdminService">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
contract="IAdmin">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
contract="IMetadataExchange" />
</service>
编辑 2:以下是 WCF 4.5 运行时在 4 核机器上设置的默认限制值。
ListenBacklog is [500]
MaxConnections is [48]
MaxConcurrentCalls is [64]
MaxConcurrentInstances is [2147483647]
MaxConcurrentSessions is [400]
编辑 3:这是使用 J.Richter 的 AsyncEnumerator 的代码:
private IEnumerator<int> DoWorkGetXXXX(AsyncEnumerator<MyResult> ae)
{
ae.ThrowOnMissingDiscardGroup(true);
IClientChannel proxy = (IClientChannel)CreateChannel(_bindingName);
bool success = false;
try
{
proxy.Open();
// The call to BeginXXX goes here
((IAcaccount)proxy).BeginGetXXX(..., ae.EndVoid(0, DiscardGetXXX), proxy);
//
yield return 1;
if (ae.IsCanceled())
{
goto Complete;
}
// Iterator was not canceled, process should continue.
// The call to EndXXX goes here
IAsyncResult ar = ae.DequeueAsyncResult();
try
{
ae.Result = ((IAcaccount)ar.AsyncState).EndGetXXX(ar);
proxy.Close();
success = true;
}
// In the mean time, we catch and rethrow :)
// If this exception occurs, we should retry a call to the service
catch (FaultException<AppFabricCachingException> retry)
{
}
// fatal Exception in data service, administrator action required...
catch (FaultException<EFExecutionException> fatal)
{
}
catch (FaultException<EFUpdateException> fatal)
{
}
catch (FaultException<EFNoRowException> nr)
{
}
catch (FaultException fe)
{
}
catch (ServiceActivationException sae)
{
}
catch (CommunicationException ce)
{
}
//
}
finally
{
// If an error occurred, abort the proxy.
if (!success)
{
proxy.Abort();
}
}
// End of operations.
Complete:
proxy = null;
}