我正在开发一个 ASP.NET MVC 项目,我想让我的控制器及其方法异步,但我不知道在哪里放置“await”。
在我的控制器的方法中,我调用了服务层的方法,该方法使用 linq 查询从数据库获取数据:
public class MyController: Controller
{
private MyEntities db = new MyEntities();
public MyController()
{
this.service = new MyService(db);
}
public List<dynamic> myMethod(FormCollection post)
{
var x = post["itemOne"];
List<dynamic> myVar = service.getFromdb(x);
return var;
}
}
Linq 查询需要很多时间,我想把
await
放在这一行的开头。
我的 Linq 查询是这样的:
public MyService : IMyService
{
public List<dynamic> getFromdb(string x)
{
var query = (from dum in db.TableOne
where dum.colOne == x
select new
{
col1 = dum.colOne,
col2 = dum.colTwo,
col3 = dum.colThree,
})
.Union(from dum2 in db.TableOne
where dum.colTwo == x
select new
{
col1 = dum2.colOne,
col2 = dum2.colTwo,
col3 = dum2.colThree,
})
.GroupBy(g => new
{
myG1 = g.colOne,
myG2 = g.colTwo,
})
.Select(s => new
{
col1 = s.Key.myG1,
col2 = s.Key.myG2,
col3 = s.Count()
})
.Join(db.TableTwo,
g => new { g.col1, g.col2 },
t => new { t.col1, t.col2 },
(g,t) => new
{
finalCol1 = g.col1,
finalCol2 = g.col2,
finalCol3 = g.col3,
finalCol4 = t.colX,
finalCol5 = t.colY,
})
.OrderByDescenging(y => new { mycol1 = y.finalCol1 , mycol2 = y.finalCol2 })
.Select(s => s);
if (SOMETHING TRUE)
{
return query.Skip(1000)
.Take(500)
.Select(s => s)
.ToList();
}
else
{
return query.Skip(2000)
.Take(100)
.Select(s => s)
.ToList();
}
}
}
我尝试将我的方法
myMethod
更改为:
public class MyController: Controller
{
public async List<dynamic> myMethod(FormCollection post)
{
var x = post["itemOne"];
List<dynamic> myVar = await service.getFromdb(x);
return var;
}
}
但在服务中我尝试更改
query
并使用await:
public async List<dynamic> getFromdb(string x)
{
var query = await (from dum in db.TableOne
.......
}
但我不知道如何将 Linq 查询更改为异步。
我想将异步添加到我的方法中,但我很困惑该怎么做
异步方法不会使您的查询更快或调用查询的方法更快。事实上,它会使调用查询的方法稍微慢一些。它将做的是允许像 Web 服务器这样的东西更快地响应,因为它将 Web 请求交给后台工作人员并恢复响应其他用户请求。 (只要该查询持续,等待的原始请求仍将等待响应,直到超时)
因此,考虑到这一点,缺少的一点是异步方法返回任务:
public async Task<List<dynamic>> myMethodAsync(FormCollection post)
{
var x = post["itemOne"];
List<dynamic> myVar = await service.getFromdb(x);
return var;
}
和
public async Task<List<dynamic>> getFromDbAsync(string x, int page, int pageSize)
{
var query = ...
return await query.Skip(page*pageSize)
.Take(pageSize)
.ToListAsync();
}
对于方法(除了控制器操作之类的东西),您应该在异步声明后加上“Async”后缀,特别是当您混合使用异步和同步变体时。如果您要在没有
getFromDbAsync()
的情况下调用 await
,您将返回 Task
,它本身可以等待或使用 WaitAll 等待。请注意,EF 的 DbContext 不是线程安全的,因此不要尝试并行化查询,例如如果使用常见的注入 DbContext
实例,则会出现此情况。当您添加 await
时,任务将自动给出一个恢复点,并且等待调用之后的代码将处理返回的数据类型。 IE。 List<dynamic>
。
var results = getFromDbAsync(someValue, 0, 500); // results = Task<List<dynamic>>
var results = await getFromDbAsync(someValue, 0, 500); // results = List<dynamic>
至于提升性能?一些简单的提示。不要试图在编码时变得聪明或懒惰。对于这样的事情来说,
dynamic
是一个巨大的危险信号。使用具体的 DTO 来预测每个特定场景。此外,当涉及到从用户输入读取操作时,仅基于他们实际需要的内容,而不是您认为他们可能想要的内容,甚至是他们所说的想要的内容。给用户过于灵活的查询能力肯定会导致项目沉没。当他们告诉你他们有老鼠问题时,它会给他们一个没有说明书的克莱莫地雷,而不是一个捕鼠器。如果 95% 的情况下更简单,具有合理数量参数的索引查询就可以完成工作,然后为这些查询构建并建立索引。构建复杂的、动态的结果和标准将导致代码速度变慢、错误较多,并且您正在追逐剩下的 5% 来满足查询结果,这实际上会使您的系统陷入困境。非索引、昂贵的查询涉及太多表,创建行锁会减慢其他所有操作的速度。然后用户发现它花费的时间太长,因此他们关闭选项卡并打开一个新选项卡,或者认为他们会在后台启动几个选项卡。