具有WCF服务引用异步功能的任务计划程序

时间:2014-07-21 20:20:09

标签: c# wcf asynchronous task-parallel-library async-await

我正在尝试使用服务引用,使用任务调度程序同时发出多个请求。该服务包括一个返回结果集的同步和异步函数。我有点困惑,我有几个初步的问题,然后我将分享我在每个问题中取得的进展。我正在使用一些日志记录,并发可视化器和提琴手进行调查。最终,我想使用反应式调度程序来尽可能多地发出请求。

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个并发请求。

3 个答案:

答案 0 :(得分:6)

  1. 是。它将允许您的应用程序通过使用更少的线程来更好地扩展。
  2. 主题。当您启动本质上异步的同步操作(例如I/O)时,您有一个阻塞的线程等待操作完成。但是,您可以在此期间使用此线程来执行CPU绑定操作。
  3. 限制并发请求数量的最简单方法是使用允许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

  • MaxConcurrentSessions:默认值为100 * ProcessorCount
  • MaxConcurrentCalls:默认值为16 * ProcessorCount
  • MaxConcurrentInstances:默认为MaxConcurrentCalls + MaxConcurrentSessions

答案 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();      
}