异步WCF呼叫花费更多时间然后同步呼叫

时间:2014-02-09 00:54:03

标签: wcf asynchronous task-parallel-library

我们有Windows服务,它从MSMQ读取消息并逐个处理。为了提高性能/吞吐量,我们转向了TPL。我们在处理消息时有几个数据库调用和WCF调用。我们观察到,在进行WCF呼叫时,前几次呼叫速度更快,但后续呼叫需要更长时间。这是示例代码。

public class TestWcf
{
    public void Process(string option)
    {
        // container for perellel tasks and WaitAll after 50 count
        TaskContainer batch = new TaskContainer(50, true);

        for (int i = 1; i <= 100; i++)
        {
            if(option.Equals("s"))
            {
                batch.Add(ProcessMessage);
            }
            else
            {
                batch.Add(ProcessMessageAsync);
            }
        }
    }

    public void ProcessMessage()
    {
        Stopwatch sw = Stopwatch.StartNew();

        PostingServiceClient client = new PostingServiceClient();
        client.UpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"),"1234567890");

        sw.Stop();
        Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds);
        //client.Close();
    }

    public void ProcessMessageAsync()
    {
        Stopwatch sw = Stopwatch.StartNew();

        PostingServiceClient client = new PostingServiceClient();
        var task = Task.Factory.FromAsync(
            client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"), "1234567890", null,
                null), client.EndUpdateArchiveStatus);
        task.Wait();

        sw.Stop();
        Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds);
        //client.Close();
    }

}

我们正在使用外部团队WCF,它托管在IIS服务器,App Pool中,目标是.Net 2.0。 WCF服务端,serviceThrottling为500,服务合同上没有定义ServiceBehavior属性。我们在同一时间运行程序,两个控制台实例一个带有Sync选项,第二个带有Async选项。同步选项完成比Async选项快得多。我的假设是,系统不会在执行异步操作时从ThreadPool释放任务。问题是,哪种方法更好(同步与异步WCF调用)或在这种情况下是否有任何不同的方法来处理WCF调用。

1 个答案:

答案 0 :(得分:0)

在我进入任何事情之前,您使用的是什么框架用于Windows服务? .Net 4.5(或更高版本)或.Net 4.0?

我问的原因是因为如果你有async/await(你需要.Net 4.5。对于 1 )那么它可以大大改变代码的简单性。

现在让我们开始做生意吧。所以你正在做的事情有些不一致。

TaskContainer到底是什么?我找不到任何文件。

此代码块

var task = Task.Factory.FromAsync(
            client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A- 4B00-96BF-E91A2B5970E3"),"1234567890", null, null), 
            client.EndUpdateArchiveStatus);

task.Wait();

NOT 异步。

由于task.Wait()调用,它是同步的,使用任务。使用Task会产生一定的开销,但在大多数情况下,异步和可伸缩性的好处将超过这个小开销。这一小部分开销要比阻止呼叫或阻止线程进行网络呼叫更好。

如果你想要一个真正的异步调用,你需要这样的东西:

var guid = Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3");

// Since I don't have a copy of the operation contract,
// I can't tell if the client call returns a specific type,
// so I'm going to assume it's `void`
var task = Task.Factory.FromAsync(client.BeginUpdateArchiveStatus, client.EndUpdateArchiveStatus, guid, null);

// If you're using .Net 4.5 or higher
// Another side note is that you'll want to return `async Task` instead of `async void` if you decide/can use `await`
await task;
sw.Stop();

// If you're not using .Net 4.0
task.ContinueWith(t =>
  {
   sw.Stop();
   // Whatever code you want to execute now.
  });

解决您的假设:

  

我的假设是,系统在执行异步操作时不会从ThreadPool释放任务。

真正异步调用一起使用时,

Task.Factory.FromAsync不会阻止ThreadPool线程。 (有很多资源可以验证这一点,但here's是我很快就提出来的。)

  

问题是,哪种方法更好(同步与异步WCF调用)或在这种情况下是否有任何不同的方法来处理WCF调用。

最好的办法是正确实施异步任务。


[1]:如果你有VS 2012或更高版本,你可以拉入NuGet包Microsoft.Bcl.Async并为.Net 4.0解决这个问题。

编辑:我刚刚意识到我遇到了一个超过1年的问题。哎呀!这就是我在略读未解答的问题时所得到的。

相关问题