Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 关于系统资源消耗和效率的异步/等待_C#_Asynchronous - Fatal编程技术网

C# 关于系统资源消耗和效率的异步/等待

C# 关于系统资源消耗和效率的异步/等待,c#,asynchronous,C#,Asynchronous,简短版本:当异步方法在循环中被调用成千上万次,并且这些方法可能调用其他异步方法时,异步调用如何扩展?我的线程池会爆炸吗? 我一直在阅读和试验TPL和Async,在阅读了大量材料之后,我仍然对一些我找不到太多信息的方面感到困惑,比如异步调用的规模如何。我会尽量直截了当地说 异步调用 对于IO,我读到使用async比使用新线程/启动任务更好,但据我所知,不使用其他线程执行异步操作是不可能的,这意味着async在某个时候必须使用其他线程/启动任务。 所以我的问题是:代码A在系统资源方面如何优于代码B

简短版本:当异步方法在循环中被调用成千上万次,并且这些方法可能调用其他异步方法时,异步调用如何扩展?我的线程池会爆炸吗?

我一直在阅读和试验TPL和Async,在阅读了大量材料之后,我仍然对一些我找不到太多信息的方面感到困惑,比如异步调用的规模如何。我会尽量直截了当地说

异步调用
对于IO,我读到使用async比使用新线程/启动任务更好,但据我所知,不使用其他线程执行异步操作是不可能的,这意味着async在某个时候必须使用其他线程/启动任务。 所以我的问题是:代码A在系统资源方面如何优于代码B

代码A

// an array with 5000 urls.
var urls = new string[5000];

// list of awaitable tasks.
var tasks = new List<Task<string>>(5000);

HttpClient httpClient;

foreach (string url in urls)
{
    tasks.Add(httpClient.GetStringAsync(url));
}

await Task.WhenAll(tasks);
...same variables as code A...

foreach (string url in urls)
{
    tasks.Add(
              Task.Factory.StartNew(() =>
              {
                // This method represents a
                // synchronous version of the GetStringAsync.
                httpClient.GetString(url);
              })
             );
}

await Task.WhenAll(tasks);
这就引出了以下问题:
1-是否应在循环中避免异步调用?
2-一次应该触发的异步调用是否有一个合理的最大值,或者触发任意数量的异步调用可以吗?这个比例如何?
3-是否使用异步方法,在后台为每个调用启动一个任务?

我用1000个URL进行了测试,使用的线程池工作线程数从未达到30个,IO完成线程数始终在5个左右

我的实践实验

我用一个简单的异步控制器创建了一个web应用程序。 该页面由一个带有文本区的表单组成,用户可以在其中输入他希望请求/处理的所有URL

提交后,使用HttpClient.geturlsync方法在循环中请求URL,就像上面的代码A一样

有趣的是,如果我提交1000个URL,完成所有请求大约需要3分钟

另一方面,如果我从3个不同的选项卡(即客户端)提交3个表单,每个表单都有1000个URL,那么结果所需的时间要长得多(大约10分钟),这确实让我感到困惑,因为根据msdn的定义,这不应该超过3分钟,特别是当同时处理所有请求时,线程池中使用的线程数大约为25,这意味着资源根本没有得到充分开发

现在的工作方式是,这种类型的应用程序远不能扩展(比如说我有大约5000个客户端一直在请求一堆URL),我看不出异步是如何触发多个IO请求的

有关该应用程序的进一步说明

客户端:
1.用户进入站点
2.在文本区域中键入1000个URL
3.提交URL

服务器端:
1.以数组形式接收URL
2.执行代码

foreach (string url in urls)
{
    tasks.Add(GetUrlAsync(url));
}

await Task.WhenAll(tasks);
//at this point the thread is
// returned to the pool to receive
// further requests.
  • 通知客户端工作已完成
  • 请,开导我吧! 多谢各位

    据我所知,在不使用不同线程的情况下执行异步操作是不可能的,这意味着异步必须在某个时候使用其他线程/启动任务

    。正如我在博客中所描述的,纯异步方法不会阻塞线程

    所以我的问题是:在系统资源方面,代码A如何比代码B更好

    A使用的线程比B少

    (顺便说一句,不要使用
    StartNew
    。它非常过时,并且具有非常危险的默认参数值。请使用
    Task。改用
    Run
    。如果您是从博客文章或文章中获得这个想法/代码的,请将这个词传下去。
    StartNew
    似乎是一种正在互联网上流行的癌症。)

    在循环中应该避免异步调用吗

    不,没关系

    一次应该触发的异步调用是否有一个合理的最大值,或者是否可以触发任意数量的异步调用

    只要您的后端资源能够处理,任何数量都可以

    这个比例如何

    NET上的异步I/O几乎总是在底层使用IOCP(I/O完成端口),这通常被认为是Windows上可用的最具可伸缩性的I/O形式

    异步方法是否在幕后为每个调用启动一个任务

    是和否。每个异步方法的执行都由一个
    任务
    实例表示,但这些实例并不表示正在运行的任务-它们不表示线程

    我调用异步任务(实际上在线程池上运行的任务)

    真把我弄糊涂了


    在测试URL请求时需要注意的一件事是,在.NET中内置了URL请求的自动节流功能。尝试设置为
    int.MaxValue

    嘿,斯蒂芬,谢谢你的回复,真的很好的信息!当我说没有额外的线程就不可能进行异步时,我不是很清楚。我指的是整个过程,而不是整个过程。我对IRP很熟悉,当IRP准备好时,一个线程就会被唤醒。但是,在请求到达驱动程序之前,该请求必须由主线程以外的线程处理,否则操作将被阻止,这意味着在某个点上正在使用一个新线程,可能由编译器创建的状态机来处理,我不知道。对吗?或者对驱动程序的请求是同步传递的吗?ServicePointManager.DefaultConnectionLimit默认为2147483647。@victor:请求是同步传递的。
    DefaultConnectionLimit
    在最新版本的.NET(4.6)上默认仅为
    int.MaxValue
    ;以前,它是
    2
    。看起来有什么东西在阻止我的请求。我在一个控制台应用程序上测试了完全相同的代码,运行时间<50秒,而使用IIS大约需要115秒。我一整天都在试图解决这个问题,但还是一无所获。这太疯狂了。有时会发出所有994请求