Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.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#_.net_Multithreading_Performance_Async Await - Fatal编程技术网

C# 异步/等待方法中耗时的任务

C# 异步/等待方法中耗时的任务,c#,.net,multithreading,performance,async-await,C#,.net,Multithreading,Performance,Async Await,与线程相比,我不太理解异步/等待的好处 在一个方法的情况下,我有一个没有异步/等待版本的操作,在其他异步操作的中间消耗20Ms的时间。p> 调用此方法1000次,因为async/await只在一个线程内执行,所以在我的测试中至少需要20ms x 1000次(使用thread.Sleep进行模拟) 是否对async/Wait有任何误解 public void Start() { Task[] task = new Task[500]; for (int i = 0; i <

与线程相比,我不太理解异步/等待的好处

在一个方法的情况下,我有一个没有异步/等待版本的操作,在其他异步操作的中间消耗20Ms的时间。p> 调用此方法1000次,因为async/await只在一个线程内执行,所以在我的测试中至少需要20ms x 1000次(使用thread.Sleep进行模拟)

是否对async/Wait有任何误解

public void Start()
{
    Task[] task = new Task[500];

    for (int i = 0; i < 500; i++)
    {
        task[i] = AsyncGet();
    }

    await Task.WhenAll(task);
}
public async Task<bool> AsyncGet()
{
    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://www.example.com");
    req.Method = "GET";
    using(HttpWebResponse res = (HttpWebResponse)await req.GetResponseAsync())
    {

        Thread.Sleep(20);//Simulate an operation without async/await version that consume a little bit time

        using (Stream responseStream = res.GetResponseStream())
        {
             StreamReader sr = new StreamReader(responseStream, Encoding.ASCII);
             string resp = await sr.ReadToEndAsync();
        }
    }
}
public void Start()
{
任务[]任务=新任务[500];
对于(int i=0;i<500;i++)
{
任务[i]=AsyncGet();
}
等待任务。WhenAll(任务);
}
公共异步任务AsyncGet()
{
HttpWebRequest请求=(HttpWebRequest)HttpWebRequest.Create(“http://www.example.com");
req.Method=“GET”;
使用(HttpWebResponse res=(HttpWebResponse)wait req.GetResponseAsync())
{
Thread.Sleep(20);//在不使用占用少量时间的异步/等待版本的情况下模拟操作
使用(Stream responseStream=res.GetResponseStream())
{
StreamReader sr=新的StreamReader(responseStream,Encoding.ASCII);
string resp=wait sr.ReadToEndAsync();
}
}
}
更新问题


如果我需要执行一些非异步/等待操作,比如在使用外部库获得http响应后操作json。避免浪费时间的最佳做法是什么?

不,不一定。如果您正在从单线程的SynchronizationContext(例如任何UI上下文,如WindowsFormsSynchronizationContext或DispatchersSynchronizationContext)调用
Start
方法,则回答是yes[*]

如果您从其他线程(比如工作线程)调用
Start
。不需要20ms x 1000。因为等待后的代码将在这种情况下执行。因此,在等待之后,可以有N个线程执行代码。其中,在您的情况下,N将小于或等于500

也就是说,不应该在异步方法中阻塞。如果需要在异步方法中使用任何同步代码,则应使用
wait Task.Run(()=>CodeThatBlocks())


*如果SynchronizationContext未被SynchronizationContext.SetSynchronizationContext覆盖,则休眠线程仍将休眠线程,而与任何异步/等待结构无关。async/await的思想是尽可能地占用每个线程,以避免创建大量等待I/O的线程。在后台执行CPU密集型操作仍然需要创建线程

换句话说,您提供的示例将导致线程冻结20毫秒,而不管它是否是异步/等待的预期用例

换句话说,要么:

  • 只需使用异步I/O。不要进行任何CPU密集型处理(也不要使用睡眠)
  • 使用线程池
是否对async/Wait有任何误解

public void Start()
{
    Task[] task = new Task[500];

    for (int i = 0; i < 500; i++)
    {
        task[i] = AsyncGet();
    }

    await Task.WhenAll(task);
}
public async Task<bool> AsyncGet()
{
    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://www.example.com");
    req.Method = "GET";
    using(HttpWebResponse res = (HttpWebResponse)await req.GetResponseAsync())
    {

        Thread.Sleep(20);//Simulate an operation without async/await version that consume a little bit time

        using (Stream responseStream = res.GetResponseStream())
        {
             StreamReader sr = new StreamReader(responseStream, Encoding.ASCII);
             string resp = await sr.ReadToEndAsync();
        }
    }
}
是的,你好像误会了。不能使用
Thread.Sleep
模拟
async wait
行为,这是一个阻塞调用。当您
等待任务时。当所有
时,多个异步请求同时执行,而不考虑底层线程

如果您想同时卸载多个请求,请使用
wait Task.Delay
测试它们,您会注意到行为的变化


您可以更进一步,在调用
GetResponseAsync
时使用
ConfigureAwait(false)
,这样方法的延续就不会将工作封送回原始的
SynchronizationContext
(这在处理自定义内容(如WinFormSynchronizationContext)时很重要)并继续在IOCP上执行。

为什么只有一个线程,它使用线程池中的任何可用线程。通常会尝试避免使用非异步持久操作。或者,如果同步上下文无关紧要,您可以对返回的
任务
对象使用
ConfigureAwait(false)
,让继续在任何上下文上继续。@eranotzap发布的代码在一个线程上运行
GetResponseAsync
可能会在内部使用另一个线程,但鉴于这是一个IO操作,他们更可能使用类似IO完成端口的东西。我写评论时没有代码。@Dirk请看下面Sriram的回答。回调可能发生在线程池中的多个线程上。您的回答也非常有用。我希望我能给出两个被接受的答案