Hie*_*ran 75 c# entity-framework async-await
我一直在寻找上面2对之间的差异,但没有发现任何文章清楚地解释它以及何时使用这一个或另一个.
那么SaveChanges()
和之间的区别是什么SaveChangesAsync()
?
之间Find()
和FindAsync()
?
在服务器端,当我们使用Async
方法时,我们还需要添加await
.因此,我不认为它在服务器端是异步的.
它只会阻止客户端浏览器上的UI阻止吗?或者它们之间有任何利弊吗?
Jac*_*ert 149
只要您需要在远程服务器上执行操作,程序就会生成请求,发送请求,然后等待响应.我将使用SaveChanges()
和SaveChangesAsync()
作为一个例子,但同样适用于Find()
和FindAsync()
.
假设您有一个myList
需要添加到数据库中的100多个项目的列表.要插入它,你的函数看起来像这样:
using(var context = new MyEDM())
{
context.MyTable.AddRange(myList);
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
首先创建一个实例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");
}
Run Code Online (Sandbox Code Playgroud)
这是一个非常小的变化,但会对代码的效率和性能产生深远的影响.那会发生什么?代码的开头是相同的,你创建一个实例MyEDM
并添加你myList
的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");
}
Run Code Online (Sandbox Code Playgroud)
为什么你会有这样的功能,我不知道,但它输出的内容显示了它是如何async await
工作的.首先让我们回顾一下发生的事情.
执行进入MyCallingFunction
,Function Starting
然后Save Starting
写入控制台,然后SaveChangesAsync()
调用该函数.此时,执行返回MyCallingFunction
并进入for循环写入'Continuing to Execute'最多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());
}
Run Code Online (Sandbox Code Playgroud)
在这里,你有四个不同的保存记录功能会在同一时间.与单个函数串行调用相比,MyCallingFunction
使用速度更快.async await
SaveRecords
我还没有涉及的一件事是await
关键字.这样做是为了阻止当前函数执行,直到Task
等待完成为止.因此,对于原始文件MyCallingFunction
,Function Complete
在SaveRecords
函数完成之前,不会将该行写入控制台.
简而言之,如果您可以选择使用async await
,那么您应该会大大提高应用程序的性能.
我剩下的解释将基于以下代码片段。
using System;
using System.Threading;
using System.Threading.Tasks;
using static System.Console;
public static class Program
{
const int N = 20;
static readonly object obj = new object();
static int counter;
public static void Job(ConsoleColor color, int multiplier = 1)
{
for (long i = 0; i < N * multiplier; i++)
{
lock (obj)
{
counter++;
ForegroundColor = color;
Write($"{Thread.CurrentThread.ManagedThreadId}");
if (counter % N == 0) WriteLine();
ResetColor();
}
Thread.Sleep(N);
}
}
static async Task JobAsync()
{
// intentionally removed
}
public static async Task Main()
{
// intentionally removed
}
}
Run Code Online (Sandbox Code Playgroud)
static async Task JobAsync()
{
Task t = Task.Run(() => Job(ConsoleColor.Red, 1));
Job(ConsoleColor.Green, 2);
await t;
Job(ConsoleColor.Blue, 1);
}
public static async Task Main()
{
Task t = JobAsync();
Job(ConsoleColor.White, 1);
await t;
}
Run Code Online (Sandbox Code Playgroud)
备注:由于 的同步部分(绿色)JobAsync
自旋时间比任务t
(红色)长,因此任务t
在 点已经完成await t
。因此,延续(蓝色)与绿色线程在同一线程上运行。(白色)的同步部分Main
会在绿色部分旋转完毕后旋转。这就是为什么异步方法中的同步部分是有问题的。
static async Task JobAsync()
{
Task t = Task.Run(() => Job(ConsoleColor.Red, 2));
Job(ConsoleColor.Green, 1);
await t;
Job(ConsoleColor.Blue, 1);
}
public static async Task Main()
{
Task t = JobAsync();
Job(ConsoleColor.White, 1);
await t;
}
Run Code Online (Sandbox Code Playgroud)
备注:本例与第一种情况相反。的同步部分(绿色)JobAsync
自旋时间短于任务t
(红色),则任务t
在 点尚未完成await t
。因此,延续(蓝色)与绿色线程在不同的线程上运行。(白色)的同步部分在Main
绿色部分旋转完毕后仍在旋转。
static async Task JobAsync()
{
Task t = Task.Run(() => Job(ConsoleColor.Red, 1));
await t;
Job(ConsoleColor.Green, 1);
Job(ConsoleColor.Blue, 1);
}
public static async Task Main()
{
Task t = JobAsync();
Job(ConsoleColor.White, 1);
await t;
}
Run Code Online (Sandbox Code Playgroud)
备注:本案例将解决前面案例中异步方法中同步部分的问题。t
立即等待任务。因此,延续(蓝色)与绿色线程在不同的线程上运行。(白色)的同步部分Main
将立即平行于 旋转JobAsync
。
如果您想添加其他案例,请随时编辑。
归档时间: |
|
查看次数: |
64067 次 |
最近记录: |