这些网络请求实际上是并发的吗?

问题描述

我有一个UrlList只有4个URL,我想使用它们发出4个并发请求。下面的代码是否真正发出了同时启动的4个请求?

我的测试似乎表明确实如此,但是我是否正确地认为实际上实际上将有4个请求同时从URL目标中检索数据,或者只是这样呢?

    static void Main(string[] args)
    {
        var t = Do_TaskWhenAll();
        t.Wait();
    }

    public static async Task Do_TaskWhenAll()
    {
        var downloadTasksQuery = from url in UrlList select Run(url);

        var downloadTasks = downloadTasksQuery.ToArray();

        Results = await Task.WhenAll(downloadTasks);
    }

    public static async Task<string> Run(string url)
    {
        var client = new WebClient();
        AddHeaders(client);

        var content = await client.DownloadStringTaskAsync(new Uri(url));

        return content;
    }

解决方法

正确,当调用ToArray时,可枚举的downloadTasksQuery将为每个URL生成一个任务,同时运行您的Web请求。

await Task.WhenAll确保仅在所有Web请求均已完成时完成任务。

您可以重写代码,以减少繁琐的工作,而实际上却要这样做,就像这样:

public static async Task Do_TaskWhenAll()
{
    var downloadTasks = from url in UrlList select Run(url);

    Results = await Task.WhenAll(downloadTasks);
}

不需要ToArray,因为Task.WhenAll会为您枚举您的枚举。

我建议您使用HttpClient而不是WebClient。使用HttpClient,您不必为每个并发请求创建新的客户端实例,因为它允许您重用同一客户端并发执行多个请求。

,

简短的回答是:如果您生成多个任务而不必等待每个任务,则它们可以同时运行,只要它们确实是异步的即可。

等待DownloadStringTaskAsync时,您的Task方法将返回Run,从而在等待响应的同时进行下一次迭代。

因此,无需等待第一个HTTP请求完成就可以发送下一个HTTP请求。

顺便说一句,您的方法可以写得更简洁:

public static async Task Do_TaskWhenAll()
{
    Results = await Task.WhenAll(UrlList.Select(Run));
}

Task.WhenAll有一个重载,它接受IEnumerable<Task<TResult>>返回的UrlList.Select(Run)

,

不,不能保证您的请求将并行执行或立即执行。

Starting a task merely queues it to the thread pool.如果池中的所有线程都被占用,则该任务将必须等待直到线程释放。

在您的情况下,由于池中有相对大量的可用线程,并且您仅对少量项目进行排队,因此池在它们进入时为它们提供服务没有问题。排队的任务越多一次,这种情况发生的可能性就越大。

如果您确实需要并发,则需要了解线程池的大小以及繁忙程度。 The ThreadPool class will help you to manage this.

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...