每当您需要在远程服务器上执行操作时,您的程序都会生成请求、发送请求,然后等待响应。我会用SaveChanges()
and SaveChangesAsync()
作为一个例子,但这同样适用于Find()
and FindAsync()
.
假设你有一个清单myList
您需要添加到数据库的 100 多个项目。要插入它,您的函数将如下所示:
using(var context = new MyEDM())
{
context.MyTable.AddRange(myList);
context.SaveChanges();
}
首先你创建一个实例MyEDM
, 添加列表myList
到餐桌上MyTable
,然后调用SaveChanges()
将更改保存到数据库。它按照您想要的方式工作,记录被提交,但您的程序在提交完成之前无法执行任何其他操作。这可能需要很长时间,具体取决于您要提交的内容。如果您要提交对记录的更改,实体必须一次提交这些更改(我曾经有一次保存更新需要 2 分钟)!
要解决此问题,您可以执行以下两种操作之一。第一个是您可以启动一个新线程来处理插入。虽然这将释放调用线程以继续执行,但您创建了一个新线程,它将坐在那里等待。不需要那种开销,这就是async await
模式解决。
对于 I/O 操作,await
很快就成为你最好的朋友。根据上面的代码部分,我们可以将其修改为:
using(var context = new MyEDM())
{
Console.WriteLine("Save Starting");
context.MyTable.AddRange(myList);
await context.SaveChangesAsync();
Console.WriteLine("Save Complete");
}
这是一个非常小的更改,但会对代码的效率和性能产生深远的影响。那么会发生什么呢?代码的开头是相同的,您创建一个实例MyEDM
并添加你的myList
to MyTable
。但当你打电话时await context.SaveChangesAsync()
,代码的执行返回调用函数!因此,当您等待所有这些记录提交时,您的代码可以继续执行。假设包含上述代码的函数的签名为public async Task SaveRecords(List<MyTable> saveList)
,调用函数可能如下所示:
public async Task MyCallingFunction()
{
Console.WriteLine("Function Starting");
Task saveTask = SaveRecords(GenerateNewRecords());
for(int i = 0; i < 1000; i++){
Console.WriteLine("Continuing to execute!");
}
await saveTask;
Console.Log("Function Complete");
}
我不知道为什么你会有这样的函数,但它的输出显示了如何async await
作品。首先让我们回顾一下发生了什么。
执行进入MyCallingFunction
, Function Starting
then Save Starting
被写入控制台,然后函数SaveChangesAsync()
被叫。此时,执行返回到MyCallingFunction
并进入 for 循环,写入“继续执行”最多 1000 次。什么时候SaveChangesAsync()
完成,执行返回到SaveRecords
功能、写作Save Complete
到控制台。一旦一切都进入SaveRecords
完成,执行将继续MyCallingFunction
是的,当时是SaveChangesAsync()
完成的。使困惑?这是一个示例输出:
Function Starting
Save Starting
Continuing to execute!
Continuing to execute!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Save Complete!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Function Complete!
或者可能:
Function Starting
Save Starting
Continuing to execute!
Continuing to execute!
Save Complete!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Function Complete!
这就是它的美丽之处async await
,当您等待某些事情完成时,您的代码可以继续运行。实际上,您将有一个更像这样的函数作为您的调用函数:
public async Task MyCallingFunction()
{
List<Task> myTasks = new List<Task>();
myTasks.Add(SaveRecords(GenerateNewRecords()));
myTasks.Add(SaveRecords2(GenerateNewRecords2()));
myTasks.Add(SaveRecords3(GenerateNewRecords3()));
myTasks.Add(SaveRecords4(GenerateNewRecords4()));
await Task.WhenAll(myTasks.ToArray());
}
在这里,您有四种不同的保存记录功能同时. MyCallingFunction
使用会更快地完成async await
比如果个人SaveRecords
函数被串联调用。
我还没有触及的一件事是await
关键词。它的作用是停止当前函数的执行,直到发生任何事情Task
您正在等待完成。所以在原来的情况下MyCallingFunction
, 线Function Complete
不会被写入控制台,直到SaveRecords
函数结束。
长话短说,如果您可以选择使用async await
,您应该这样做,因为它将大大提高应用程序的性能。