内部有多个异步调用的异步WCF服务

时间:2012-07-19 19:25:25

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

我在WCF中有一个Web服务,它使用一些外部Web服务,所以我想做的是使这个服务异步以释放线程,等待所有外部服务的完成,然后返回结果给客户。

使用Framework 4.0

public class MyService : IMyService
{
    public IAsyncResult BeginDoWork(int count, AsyncCallback callback, object serviceState)
    {    
        var proxyOne = new Gateway.BackendOperation.BackendOperationOneSoapClient();
        var proxyTwo = new Gateway.BackendOperationTwo.OperationTwoSoapClient();

        var taskOne = Task<int>.Factory.FromAsync(proxyOne.BeginGetNumber, proxyOne.EndGetNumber, 10, serviceState);
        var taskTwo = Task<int>.Factory.FromAsync(proxyTwo.BeginGetNumber, proxyTwo.EndGetNumber, 10, serviceState);

        var tasks = new Queue<Task<int>>();
        tasks.Enqueue(taskOne);
        tasks.Enqueue(taskTwo);

        return Task.Factory.ContinueWhenAll(tasks.ToArray(), innerTasks =>
        {
            var tcs = new TaskCompletionSource<int>(serviceState);
            int sum = 0;

            foreach (var innerTask in innerTasks)
            {
                if (innerTask.IsFaulted)
                {
                    tcs.SetException(innerTask.Exception);
                    callback(tcs.Task);
                    return;
                }

                if (innerTask.IsCompleted)
                {
                    sum = innerTask.Result;
                }
            }

            tcs.SetResult(sum);

            callback(tcs.Task);
        });
    }

    public int EndDoWork(IAsyncResult result)
    {
        try
        {
            return ((Task<int>)result).Result;
        }
        catch (AggregateException ex)
        {
            throw ex.InnerException;
        }

    }
}

我的问题是:

  1. 此代码使用三个线程:一个在实例中执行 BeginDoWork,另一个在代码输入时实例化的 在匿名方法ContinueWhenAll里面,最后一个在什么时候 执行回调,在本例中为EndDoWork。这是正确的还是 我在电话上做错了什么?我应该使用任何 同步上下文?注意:同步上下文为null 在主线程上。

  2. 如果我之间“共享”信息会发生什么 线程,例如,回调函数?这会导致一个 性能问题或匿名方法就像我的闭包 可以共享数据吗?

  3. 使用Framework 4.5和Async并等待

    现在使用Framework 4.5,代码看起来比以前简单得多:

        public async Task<int> DoWorkAsync(int count)
        {
            var proxyOne = new Backend.ServiceOne.ServiceOneClient();
            var proxyTwo = new Backend.ServiceTwo.ServiceTwoClient();
    
            var doWorkOne = proxyOne.DoWorkAsync(count);
            var doWorkTwo = proxyTwo.DoWorkAsync(count);
    
            var result = await Task.WhenAll(doWorkOne, doWorkTwo);
    
            return doWorkOne.Result + doWorkTwo.Result;
        }
    

    但在这种情况下,当我调试应用程序时,我总是看到代码在同一个线程上执行。所以我的问题是:

    3 ..当我在等待“等待”代码时,该线程是否已发布并返回线程池以执行更多请求?

    3.1。如果是这样,我想当我从await Task获得结果时,执行在与之前调用相同的线程上完成。那可能吗?如果该线程正在处理另一个请求会发生什么?

    3.2如果不是,我如何释放线程以使用Asycn和Await模式将其发送回线程池?

    谢谢!

1 个答案:

答案 0 :(得分:2)

  

1。此代码使用三个线程:一个在BeginDoWork中实例化,另一个在代码进入匿名方法ContinueWhenAll时实例化,另一个在执行回调时实例化,在本例中为EndDoWork。这是正确的还是我在电话上做错了什么?我应该使用任何同步上下文吗?

最好用“任务”而不是“线程”来思考。你在这里有三个任务,每个任务将在线程池上运行,一次一个。

  

2。如果我在线程之间“共享”信息,例如回调函数,会发生什么?这会导致性能问题,还是匿名方法就像是一个可以共享数据的闭包?

您不必担心同步,因为这些任务中的每一个都无法同时运行。 BeginDoWork在返回之前注册延续,因此在延续可以运行时已经实际完成了。在继续完成之前,可能不会调用EndDoWork;但即使它是,它也会阻止,直到延续完成。

(从技术上讲,延续可以BeginDoWork完成之前开始运行,但BeginDoWork只是在那时返回,所以没关系。)

  

3。当我在等待“等待”代码时,该线程是否被释放并返回线程池以执行更多请求?

  

3.1。如果是这样,我想当我从await Task获得结果时,执行在与之前调用相同的线程上完成。那可能吗?如果该线程正在处理另一个请求会发生什么?

没有。您的主机(在本例中为ASP.NET)可以在它碰巧可用的任何线程上继续async方法。

这是非常安全的,因为一次只有一个线程正在执行

P.S。我推荐

var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return result[0] + result[1];

而不是

var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return doWorkOne.Result + doWorkTwo.Result;

因为Task.Result编程应该避免使用async