await (async) Task 和 await Task 有什么区别?
What's the difference between await (async) Task and await Task?
等待异步任务和等待简单任务有什么区别?
更好地理解我的疑问的示例代码:
WEBAPI 调用:
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);
}
performance/hangs的区别在哪里?
编辑:我只使用以不同方式调用的异步代码
案例 B 不是异步等待。
如果你有一个线程,并且这个线程必须开始一个相当漫长的过程,在这个过程中它除了等待之外别无他法,通常是因为其他人/其他东西执行了操作,那么你的线程可能会决定做其他事情而不是等待操作完成。
这方面的典型操作是将数据写入磁盘、请求 Internet 页面、进行数据库查询等。在非常低的级别上,您的线程只能等待操作完成。
例如,将数据写入文件时,线程的世界会在它命令硬件写入数据时结束。您的线程不必移动硬盘中的写入臂,等待正确的扇区位于写入臂下,发送写入信号等。您的线程只能等待完成。
这期间你的线程可以开始干别的事情,有空的时候可以检查写操作是否完成,然后执行写操作后的语句。
这种情况在 this interview with Eric Lippert. 中的厨房类比中有所描述,其中厨师不等待茶水煮沸,而是开始切面包。在中间某处搜索 async-await
无论何时调用异步函数,您都可以确定有等待。事实上,如果您编写异步函数但忘记在其中某处等待,您的编译器会抱怨。
只要您的线程进入异步函数,它就会继续工作,直到看到等待。这表明线程不应在等待的任务完成之前执行 await 之后的语句 returns.
通常您的线程不会执行任何操作。但是在 async-await 中,您的线程会在其调用堆栈中上升以在调用之后执行函数,直到它看到等待。它再次进入调用堆栈,执行函数直到它看到 await 等
在大家等待之后,线程不能做任何事情,返回到线程池。如果我们正在等待的进程(硬盘写入)完成,一个线程被提取到线程池中。此线程将继续执行 await 之后的语句,直到它再次看到 await。
这在Stephen Cleary: There is no thread
的文章中有描述
您经常会在异步调用后立即看到等待:
var fetchedItems = await stream.ReadAsync();
在这种情况下,等待是在调用之后立即进行的。在 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,这可以在调试器中看到。这个其他线程具有原始线程的“上下文”,效果是它可以像原始线程一样工作。您不必担心多线程、互斥锁、竞争条件等。对于程序的设计者来说,就好像一个线程可以完成所有的事情。
但是案例 B 不是异步等待。在这里,您从可用线程池中订购一个线程来做某事。与此同时,您的线程可以自由地做其他事情,直到它等待另一个线程执行的任务完成。因为您的函数不是异步的,所以无论何时您的线程开始等待,它都不会进入其调用堆栈以查看它是否可以做其他事情,它实际上是在等待并且什么都不做,直到任务完成。
This article about async-await 由非常有帮助的 Stephen Cleary 撰写,帮助我了解如何使用 async-await
等待异步任务和等待简单任务有什么区别?
更好地理解我的疑问的示例代码:
WEBAPI 调用:
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);
}
performance/hangs的区别在哪里?
编辑:我只使用以不同方式调用的异步代码
案例 B 不是异步等待。
如果你有一个线程,并且这个线程必须开始一个相当漫长的过程,在这个过程中它除了等待之外别无他法,通常是因为其他人/其他东西执行了操作,那么你的线程可能会决定做其他事情而不是等待操作完成。
这方面的典型操作是将数据写入磁盘、请求 Internet 页面、进行数据库查询等。在非常低的级别上,您的线程只能等待操作完成。
例如,将数据写入文件时,线程的世界会在它命令硬件写入数据时结束。您的线程不必移动硬盘中的写入臂,等待正确的扇区位于写入臂下,发送写入信号等。您的线程只能等待完成。
这期间你的线程可以开始干别的事情,有空的时候可以检查写操作是否完成,然后执行写操作后的语句。
这种情况在 this interview with Eric Lippert. 中的厨房类比中有所描述,其中厨师不等待茶水煮沸,而是开始切面包。在中间某处搜索 async-await
无论何时调用异步函数,您都可以确定有等待。事实上,如果您编写异步函数但忘记在其中某处等待,您的编译器会抱怨。
只要您的线程进入异步函数,它就会继续工作,直到看到等待。这表明线程不应在等待的任务完成之前执行 await 之后的语句 returns.
通常您的线程不会执行任何操作。但是在 async-await 中,您的线程会在其调用堆栈中上升以在调用之后执行函数,直到它看到等待。它再次进入调用堆栈,执行函数直到它看到 await 等
在大家等待之后,线程不能做任何事情,返回到线程池。如果我们正在等待的进程(硬盘写入)完成,一个线程被提取到线程池中。此线程将继续执行 await 之后的语句,直到它再次看到 await。
这在Stephen Cleary: There is no thread
的文章中有描述您经常会在异步调用后立即看到等待:
var fetchedItems = await stream.ReadAsync();
在这种情况下,等待是在调用之后立即进行的。在 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,这可以在调试器中看到。这个其他线程具有原始线程的“上下文”,效果是它可以像原始线程一样工作。您不必担心多线程、互斥锁、竞争条件等。对于程序的设计者来说,就好像一个线程可以完成所有的事情。
但是案例 B 不是异步等待。在这里,您从可用线程池中订购一个线程来做某事。与此同时,您的线程可以自由地做其他事情,直到它等待另一个线程执行的任务完成。因为您的函数不是异步的,所以无论何时您的线程开始等待,它都不会进入其调用堆栈以查看它是否可以做其他事情,它实际上是在等待并且什么都不做,直到任务完成。
This article about async-await 由非常有帮助的 Stephen Cleary 撰写,帮助我了解如何使用 async-await