await(异步)任务和等待任务之间有什么区别?

时间:2017-10-31 11:50:54

标签: c# asynchronous asp.net-web-api async-await task-parallel-library

等待异步任务或等待简单任务有什么区别?

示例代码,以便更好地保留我的dubt:

的WebAPI-CALL:

public async Task<IHttpActionResult> GetFiles()
{
   //Simple call for clean code, i think
   var t = DownloadFile(1);
   return Ok(await t);
}

案例A:

public static async Task<File> DownloadFile(int fileId){
  //Some checks if i can download the file

  //Some other checks if the file exist

  return await TakeFile(fileId);
}

案例B:

//In this case i can use ref and out parameters and await the task!

public static Task<File> DownloadFile(int fileId){
  //Some checks if i can download the file

  //Some other checks if the file exist

  var t = Task.Run(() => TakeFile(fileId));
  t.Wait();
  return Task.FromResult(t.Result);
}

性能/挂起的区别在哪里?

编辑:我只使用以不同方式调用的异步代码

1 个答案:

答案 0 :(得分:0)

案例B不是异步等待。

如果你有一个线程,并且这个线程必须启动一个相当漫长的过程,在这个过程中它无所事事但是等待,通常是因为有人/其他人执行操作,那么你的线程可以决定做别的而不是等待手术完成。

这方面的典型操作是将数据写入磁盘,请求网页,进行数据库查询等。在非常低的级别上,您的线程无法做任何事情,只能等待操作完成。

例如,当将数据写入文件时,线程的世界在命令硬件写入数据时结束。你的线程不必移动硬盘中的写臂,等到正确的扇区在写臂下,发送写信号等。你的线程除了等待完成之外什么也做不了

在此期间,您的线程可以开始执行其他操作,并且当它有时间时,它可以检查写操作是否完成,并在写操作之后执行语句。

这种情况在this interview with Eric Lippert.中的厨房类比中描述,其中厨师不等待茶水煮沸,而是开始切片面包。在中间某处搜索async-await

无论何时调用异步函数,您都可以确定存在等待。实际上,如果您编写异步函数但忘记等待其中的某个地方,您的编译器会抱怨。

每当你的线程进入异步函数时,它会继续工作直到它看到await。这表明在等待的任务完成并返回之前,线程不应在等待之后执行语句。

通常你的线程不会做任何事情。但是在async中等待你的线程上升到它的调用堆栈以在调用之后执行函数,直到它看到await。它再次向上调用堆栈,执行函数直到它看到await等等。

在每个人都在等待之后,线程不能再做任何事情并返回到线程池。如果我们正在等待的进程(硬盘写入)完成,则会将一个线程提取到线程池。该线程将在等待之后继续执行语句,直到它再次看到等待。

Stephen Cleary: There is no thread

的文章对此进行了描述

在异步调用之后,您经常会看到等待:

var fetchedItems = await stream.ReadAsync();

在这种情况下,await紧接在通话之后。在完成ReadAsync之前,该线程在此功能中不会做太多。

但有时你的功能不需要立即得到结果:

var fetchTask = stream.ReadAsync()
// because there is no await, instead of doing nothing the thread can do the following:
DisplayWaitIcon();
CalculateSomething();

// now the thread needs the result. So it starts awaiting:
var fetchedItems = await fetchTask;
// here we know that the ReadAsync is finished,
// and the returned items are available in fetchedItems.
ProcessFetchedItems(fetchedItems);

你知道在我的故事中只有一个线程正在做所有的事情。如果你仔细观察,它不必是完成所有东西的同一个线程,它可能是一个不同的线程。

如果您调查ThreadId,可以在调试器中看到这一点。这个其他线程具有原始线程的&#39; context`,其效果是它可以表现为原始线程。你不必担心多线程,互斥,竞争条件等。对于程序的设计者来说,就好像一个线程可以完成所有的工作。

案例B然而不是异步等待。在这里,您可以从可用线程池中订购一个线程来执行某些操作。同时,您的线程可以自由地执行其他操作,直到它等待另一个线程执行的任务完成为止。因为你的函数不是异步的,所以当你的线程开始等待时,它不会上升到它的调用堆栈以查看它是否可以执行其他操作,它确实等待并且在任务完成之前什么都不做。

由非常有帮助的Stephen Cleary撰写的

This article about async-await帮助我了解了如何使用async-await