如何加快任务 与HttpClient的(How to speed up task wit

2019-09-18 15:51发布

我有我需要做〜100 HTTP API调用服务器和处理结果的过程。 我已经把这个commandexecutor它建立的命令列表,然后运行它们异步。 为了使约100电话,并解析结果接管1分钟。 1个请求使用浏览器给我〜100毫秒的响应。 你可能会认为〜100接听的话会有10秒左右。 我相信,我做错了什么,而这应该更快。

 public static class CommandExecutor
 {
    private static readonly ThreadLocal<List<Command>> CommandsToExecute =
        new ThreadLocal<List<Command>>(() => new List<Command>());
    private static readonly ThreadLocal<List<Task<List<Candidate>>>> Tasks =
        new ThreadLocal<List<Task<List<Candidate>>>>(() => new List<Task<List<Candidate>>>());

    public static void ExecuteLater(Command command)
    {
        CommandsToExecute.Value.Add(command);
    }

    public static void StartExecuting()
    {
        foreach (var command in CommandsToExecute.Value)
        {
            Tasks.Value.Add(Task.Factory.StartNew<List<Candidate>>(command.GetResult));
        }

        Task.WaitAll(Tasks.Value.ToArray());
    }

    public static List<Candidate> Result()
    {
        return Tasks.Value.Where(x => x.Result != null)
                          .SelectMany(x => x.Result)
                          .ToList();
    }
}

那我传递到这个列表中的命令创建一个新的HttpClient,与URL调用客户端上的getasync,将字符串转换响应对象,然后保湿的字段。

    protected void Initialize()
    {
        _httpClient = new HttpClient();
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
    }

    protected override void Execute()
    {
        Initialize();

        var task = _httpClient.GetAsync(string.Format(Url, Input));
        Result = ConvertResponseToObjectAsync(task).Result;
        Result.ForEach(x => x.prop = value);
    }

    private static Task<Model> ConvertResponseToObjectAsync(Task<HttpResponseMessage> task)
    {
        return task.Result.Content.ReadAsAsync<Model>(
           new MediaTypeFormatter[]
           {
                 new Formatter()
           });
    }

你可以拿起我的瓶颈或对如何加快这任何建议。

编辑做了这些改变使得它降低到4秒。

protected override void Execute()
    {
        Initialize();

        _httpClient.GetAsync(string.Format(Url, Input))
        .ContinueWith(httpResponse => ConvertResponseToObjectAsync(httpResponse)
        .ContinueWith(ProcessResult));
    }

    protected void ProcessResult(Task<Model> model)
    {
        Result = model.Result;
        Result.ForEach(x => x.prop = value);
    }

Answer 1:

避免使用task.Result在ConvertResponseToObjectAsync,然后再Execute 。 相反,这些连锁在原来的GetAsync与任务ContinueWith

因为它代表今天, Result将阻止当前线程的执行,直到另一个任务完成。 然而,你的线程池会很快通过等待上无处可运行其他任务任务备份。 最终(后等待第二次),线程池会增加一个额外的线程来运行,因此这将最终完成,但它几乎没有有效的。

作为一般原则,应该避免以往任何时候都访问Task.Result除了在任务中延续。

作为奖励,你可能不希望使用ThreadLocalStorageThreadLocalStorage将存储在它在那里访问的每个线程上项目的一个实例。 在这种情况下,它看起来像你想存储的一个线程安全的,但共享的形式。 我会建议ConcurrentQueue对于这样的事情。



Answer 2:

停止创建新的HttpClient实例。 每次你配置一个HttpClient的实例它关闭TCP / IP连接。 创建一个HttpClient的实例,并重新使用它为每个请求。 HttpClient的可以同时在多个不同线程的多个请求。



文章来源: How to speed up task with httpclient