我正在尝试使用服务引用,使用任务调度程序同时发出多个请求。该服务包括一个返回结果集的同步和异步函数。我有点困惑,我有几个初步的问题,然后我将分享我在每个问题中取得的进展。我正在使用一些日志记录,并发可视化器和提琴手进行调查。最终,我想使用反应式调度程序来尽可能多地发出请求。
1)我应该使用异步功能来发出所有请求吗?
2)如果我在多个任务中使用同步功能,那么可能会使我的线程计数匮乏的有限资源是什么?
这是我到目前为止所做的:
var myScheduler = new myScheduler();
var myFactory = new Factory(myScheduler);
var myClientProxy = new ClientProxy();
var tasks = new List<Task<Response>>();
foreach( var request in Requests )
{
var localrequest = request;
tasks.Add( myFactory.StartNew( () =>
{
// log stuff
return client.GetResponsesAsync( localTransaction.Request );
// log some more stuff
}).Unwrap() );
}
Task.WaitAll( tasks.ToArray() );
// process all the requests after they are done
这会运行,但根据fiddler,它只是尝试立即执行所有请求。它可能是调度程序,但我相信我做的更多。
我还尝试在没有unwrap命令的情况下实现它,而是使用异步await委托,它也做同样的事情。我也试过引用.result,这似乎顺序完成。使用与调度程序/工厂的非同步服务函数调用,每个客户端同时只能同时获得大约20个并发请求。
答案 0 :(得分:6)
I/O
)时,您有一个阻塞的线程等待操作完成。但是,您可以在此期间使用此线程来执行CPU绑定操作。限制并发请求数量的最简单方法是使用允许SemaphoreSlim
输入asynchronously wait的{{3}}:
async Task ConsumeService()
{
var client = new ClientProxy();
var semaphore = new SemaphoreSlim(100);
var tasks = Requests.Select(async request =>
{
await semaphore.WaitAsync();
try
{
return await client.GetResponsesAsync(request);
}
finally
{
semaphore.Release();
}
}).ToList();
await Task.WhenAll(tasks);
// TODO: Process responses...
}
答案 1 :(得分:3)
无论您如何调用WCF服务,无论是异步调用还是同步调用,您都将受到WCF serviceThrottling限制的约束。您应该查看这些设置并可能将它们调高(如果由于某种原因将它们设置为低值),在.NET4中默认值非常好,但在旧版本的.NET框架中,这些默认值更为保守比.NET4。
.NET 4.0
答案 2 :(得分:3)
1)是。 2.)是。
如果您想控制同时请求的数量,可以尝试使用Stephen Toub的ForEachAsync
method。它允许您控制同时处理的任务数。
public static class Extensions
{
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate {
using (partition)
while (partition.MoveNext())
await body(partition.Current);
}));
}
}
void Main()
{
var myClientProxy = new ClientProxy();
var responses = new List<Response>();
// Max 10 concurrent requests
Requests.ForEachAsync<Request>(10, async (r) =>
{
var response = await client.GetResponsesAsync( localTransaction.Request );
responses.Add(response);
}).Wait();
}