c# - 调用 Web 服务时最有效的 C# Tasks 和 Continuations 配置?

标签 c# .net performance task-parallel-library threadpool

我正在创建一个与实时网络 API 对话的网络客户端。

客户端必须每秒进行多次不同的调用并提供 Task<TResult>返回到每个客户端组件,以便客户端可以决定是否阻止:

public Task<TResult> Execute<TResult>(IOperation<TResult> operation);

调用 API 的过程是这样运行的:

  1. 将(小的,小于1KB)请求序列化为Json
  2. 使用 HttpClient 发送请求
  3. 成功后反序列化为TResult (Json 可能有几百 KB,但通常要小得多)并返回

在我的测试中,选择将每个步骤包含在任务工作流中的位置(以及因此在哪个线程上)对性能有重大影响。

到目前为止,我发现最快的设置是这样的(半伪代码,为简洁起见省略了通用类型参数):

// serialize on main thread
var requestString = JsonConvert.SerializeObject(request);
// create message - omitted
var post = Task.Factory.StartNew(() => this.client.SendAsync(requestMessage)).Unwrap();
return post.ContinueWith(response =>
            {
                var jsonString = response.Result.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject(jsonString.Result);
            });

最慢的是整个过程在单个任务中执行的设置:

return Task.Factory.StartNew((request) => 
            {
                var requestString = JsonConvert.SerializeObject(request);
                // create message - omitted
                var post = client.SendAsync(requestMessage);
                var jsonString = post.Result.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject(jsonString.Result);
            })

我原以为最后一种方法可能是最快的,因为您为每个请求创建了一个后台线程。我的假设是,由于调用阻塞,这不允许 TPL 最有效地使用可用线程。

那么,关于什么应该放在任务中以及什么应该放在任务之外或延续中,是否有一般规则?

在这种特定情况下,我可以尝试进一步优化吗?

最佳答案

您根本不需要使用 Task.Factory.StartNew,因为 SendAsync 已经返回一个 Task:

var post = this.client.SendAsync(requestMessage);
return post.ContinueWith(response =>
        {
            var jsonString = response.Result.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject(jsonString.Result);
        });

这实际上会更有效率,因为它根本不需要 ThreadPool 线程。

请注意,您可以使用 async/await 进一步优化它(以保持响应异步):

var response = await this.client.SendAsync(requestMessage);
var jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject(jsonString);

这也可以通过 TPL 延续来编写,但这需要从 ReadAsStringAsync 返回(展开的)任务,然后在其上发布新的延续以获得最终字符串。

关于c# - 调用 Web 服务时最有效的 C# Tasks 和 Continuations 配置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15208277/

相关文章:

c# - 垃圾收集保证

c# - ASP.NET Web API 性能问题

c# - 如何解决 '...is a ' type', which is not valid in the given context'? (C#)

jquery - 如果多次使用 $(this) ,我应该在 jQuery 中缓存它吗?

arrays - 矩阵中的累积和

c# - 动态加载具有相同功能的不同库

.net - 有没有更简单的方法在 .net 中创建注册表 volatile 子项?

c# - 从字符串开头提取小数

c# - 用 C# 代码将 excel 文件保存到 csv 文件

ruby - 如何改善 jRuby 加载时间?