在WCF或WebAPI方法(IIS)中返回“Task <int>”而不是“int”的好处</int>

时间:2014-02-24 12:18:26

标签: c# wcf iis task-parallel-library task

考虑一个耗时的同步方法“Foo”:

public int Foo(int id)
{
    // Do some expensive calculation
    return 42;
}

在IIS中托管的WCF服务名为“FooService”,称为“Foo”:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class FooService 
{
    public Task<int> GetFoo(int id)
    {
        return Task.Factory.StartNew(() => return Foo(id));
    }

    public int GetFoo2(int id)
    {
        return Foo(id);
    }
}

如果我开始并返回一个Foo任务,我会获得任何好处吗?喜欢 - 我是否减少了I / O线程的负载?

3 个答案:

答案 0 :(得分:4)

WCF中的任务提供了比APM模式(BeginXX / EndXX)更方便的API。为什么要在WCF中使用异步调用?因为,如果正确完成,它将导致更好的线程利用率,从而使您的应用程序更具可扩展性。

在客户端,拥有基于任务的服务合同,可以更轻松地在不阻塞线程的情况下调用服务,等待调用返回。即使操作是服务器端的同步CPU绑定操作,客户端也可以从执行任务中受益。此外,通过调用Task.Wait()Task<T>.Result,通过任务,再次使呼叫同步变得非常简单。

在服务方面,基于任务的操作在以下几种情况下非常有用:

  • 您希望并行化某些受CPU限制的操作
  • 您正在进行IO(例如,呼叫其他服务,阅读文件等)
  • 以上
  • 的任何组合

每次调用WCF操作时,WCF都会从线程池中获取一个线程来处理请求。所以没有必要调用StartNew,它将操作排队到线程池(完全冗余的开销):

public Task<int> GetFoo(int id)
{
    return Task.Factory.StartNew(() => return Foo(id));
}

相反,您可以使用FromResult创建一个已完成的任务对象:

public Task<int> GetFoo(int id)
{
    return Task.FromResult(new Foo(id));
}

最后,如果上述用例都不相关,您的客户端API需要同步,那么使用任务是没有意义的。

答案 1 :(得分:2)

在我看来,不,你不会从你的帖子中描述的分离任务线程来完成工作中获得任何好处。原因是:使用WSHttpBinding或BasicHTTPBinding定义的每个WCF Web服务(不能与其他人交谈)将为每个传入请求创建自己的独立线程,因此我没有看到优势。因此,如果10个请求在12:00:01:00发出,则每个请求将自动从WCF获得它自己的线程。

现在,如果在每个单一请求中你想要线程加速一些重复的,耗时的任务,那么你显然可以通过Task设置和管理线程,但这就是它。

答案 2 :(得分:1)

请定义耗时的同步方法

异步操作的开销不可忽略。如果您正在执行 IO绑定操作(调用另一个Web服务/ API,读取文件,从数据库读取大量数据或运行慢速查询),则只应使用任务。

在服务器端使用异步编程与客户端不同。我们不关心UI线程,而是关注可伸缩性。在服务器端使用异步编程将允许您运行数千个并发请求。

这是非常重要的,因为IIS 7,如here

所述
  

...在IIS 7.0集成模式下,ASP.NET限制了数量   并发执行请求。这种差异只会影响到   请求是异步的(请求要么是异步的   处理程序或管道中的模块异步完成)。   显然如果reqeusts是同步的,那么数量   并发执行请求与线程数相同   并发执行请求,但是如果请求是异步的   那么这两个数字可能会有很大不同,因为你可以有很多   比线程更多的请求。

注意:从.net 4.5开始,最好使用Task.Run。