.net 4.5 中的异步和同步之间的差异

本文关键字:同步 之间 异步 net | 更新日期: 2023-09-27 18:36:08

在我阅读有关 .Net 4.5 中的异步编程时,asyncawait关键字我在这里读了以下段落

处理异步请求

在 Web 应用程序中,在 启动或具有突发负载(并发性突然增加), 使这些 Web 服务调用异步将增加 应用程序的响应能力。异步请求需要 处理时间与同步请求相同。为 例如,如果请求发出需要两个 Web 服务调用 秒完成,请求需要两秒钟,无论它是 同步或异步执行。但是,在 异步调用,不会阻止线程响应其他线程 请求,同时等待第一个请求完成。因此 异步请求可防止请求排队和线程池增长 当有许多并发请求调用长时间运行时 操作。

对于粗体字,我无法理解异步请求处理所需的时间与同步请求相同?

例如:

public async Task MyMethod()
{
    Task<int> longRunningTask = LongRunningOperation();
    //indeed you can do independent to the int result work here 
    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}
public async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); //1 seconds delay
    return 1;
}

据我了解,LongRunningOperation()从调用这里的第一行开始执行Task<int> longRunningTask = LongRunningOperation();并在调用await后返回值,所以从我的角度来看,异步代码比同步代码快,对吗?

另一个问题:

据我了解,正在执行的主线程MyMethod()没有阻塞等待LongRunningOperation()完成,但它返回到线程池以服务于另一个请求。 那么是否有另一个线程分配给LongRunningOperation();来执行它呢?

如果是,那么异步编程和多线程编程有什么区别?

更新:

假设代码变成这样:

public async Task MyMethod()
    {
        Task<int> longRunningTask = LongRunningOperation();
        //indeed you can do independent to the int result work here 
        DoIndependentWork();
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine(result);
    }
    public async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        DoSomeWorkNeedsExecution();
        await Task.Delay(1000); //1 seconds delay
        return 1;
    }

在这种情况下,LongRunningOperation()会在执行过程中DoIndependentWork()被另一个线程执行吗?

.net 4.5 中的异步和同步之间的差异

异步操作速度不快。如果您异步等待 10 秒(即 await Task.Delay(10000) ) 或同步(即 Thread.Sleep(10000)这将需要相同的 10 秒。唯一的区别是第一个在等待时不会支撑线程,但第二个会

现在,如果您启动一个任务并且不等待它立即完成,则可以使用相同的线程来执行其他工作,但它不会"加速"异步操作的运行:

var task = Task.Delay(10000);
// processing
await task; // will complete only after 10 seconds

关于你的第二个问题:Task.Delay(像其他真正的异步操作一样)不需要执行线程,因此没有线程。 Task.Delay是使用您启动的System.Threading.Timer实现的,并在完成后引发一个事件,同时它不需要线程,因为没有要执行的代码。

因此,当正在运行的线程到达MyMethod await longRunningTask时,它就会被释放(只要longRunningTask尚未完成)。如果它是一个ThreadPool线程,它将返回到ThreadPool,在那里它可以处理应用程序中的一些其他代码。


关于更新,流程将是这样:

  • MyMethod开始处理
  • LongRunningOperation开始处理
  • DoSomeWorkNeedsExecution在调用线程上执行
  • LongRunningOperation中达到await,因此返回热任务。
  • DoIndependentWork由同一个调用线程执行(LongRunningOperation仍在"运行",不需要线程)
  • MyMethod达到await。如果原始任务完成,则同一线程将同步进行,如果没有,则将返回最终将完成的热任务。

因此,您正在使用async-await的事实允许您使用线程,否则该线程将被阻塞,等待同步等待执行的 CPU 密集型工作。

考虑以下两者之间的区别:

Thread.Sleep(1000);

await Task.Delay(1000);

两者都需要一秒钟才能运行。然而,在前一种情况下,当前线程将被阻止(并且其所有资源都无用),而在后一种情况下,当前线程可以做其他有用的事情(例如,为另一个请求提供服务)。

异步性不是要加快单个指令序列的速度,而是能够在同步代码阻塞时执行操作。

另一个问题

释放的线程

将用于其他事项;在操作完成之前,不会分配任何线程。这是可能的,因为底层操作系统本身是异步的。在上面的示例中,使用了一个计时器,该计时器在线程空闲时发出信号,而不是线程停止用于内部。

(建立在I3arnon的答案之上)

总体而言,同步操作和使用async-await的操作需要相同的时间,这并非绝对正确。

async-await中涉及一些额外的逻辑。涉及对已完成的等待者和状态机的检查。这使得某些异步操作比相应的同步操作花费更多的时间。

另一方面,大多数适合async-await的操作自然是异步的,并且涉及一些额外的处理以使其外观和感觉同步。在这些情况下,异步操作比同步操作花费的时间更少。

关于这个问题的引用与 Web 应用程序有关。对于 Web 应用程序,异步操作更多的是在可接受的时间内提供最大数量的请求,而不是为每个请求节省几微秒。另一方面,如果涉及上下文切换,最终会花费更多时间,这就是为什么在 Web 应用程序中使用 Task.Run 对应用程序弊大于利的原因。

如果您想了解有关async-awit的更多信息,请阅读我的async-awit策展上的文章。