可以Lazy<比;和Task<比;组合以延迟数据库查找
本文关键字:延迟 数据库 查找 Lazy 可以 Task 组合 | 更新日期: 2023-09-27 18:19:24
我已经编写了下面这个问题的简化版本。所以我有这个服务,在方法DoSomething
中,我想做一个同步检查(IsTrue()
方法),然后是async
调用(数据库查找)。
如果syncResult
为假,我只想做数据库查找(EF6异步选择-由this.SuperSlowThing
模拟)。这可以通过使用&&
来完成,只有在syncResult
为真时才会继续使用asyncResult
。
我的问题是:这是解决这个问题的好方法吗?如果有,有没有更简单的方法?
internal class MyService
{
public void DoSomething(bool someValue)
{
var syncResult = this.IsTrue(someValue);
var asyncResult = new Lazy<Task<string>>(this.SuperSlowThing);
if (syncResult && asyncResult.Value.Result.Length > 0)
{
Console.WriteLine("Did SuperSlowThing - result is " + asyncResult.Value.Result);
}
else
{
Console.WriteLine("Didn't do SuperSlowThing");
}
}
private bool IsTrue(bool someValue)
{
return someValue;
}
private Task<string> SuperSlowThing()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
while (sw.ElapsedMilliseconds < 5000)
{
Thread.Sleep(500);
Console.WriteLine("Delaying");
}
return Task.FromResult("Done!");
}
}
编辑
那么让我来详细说明一下这些代码在现实生活中的作用。DoSomething
方法实际上是一个数据库查找。如果someValue
是网络中存在的某个数字。然后在数据库中查找表a中的数字。这是同步操作。
如果在表a中找到结果,则返回该结果,否则查找表b中的数字。
如果在web中没有找到someValue
的编号。
我认为这里没有真正的理由使用Lazy
。你可以先检查syncResult
然后再检查asyncResult
:
public async Task DoSomething(bool someValue)
{
if (IsTrue(someValue) && await SuperSlowThing().Length > 0)
{
// ..
}
else
{
// ..
}
}
或者一个更好的,更可读的版本:
public async Task DoSomething(bool someValue)
{
bool condition = false;
if (IsTrue(someValue))
{
var result = await SuperSlowThing();
if (result.Length > 0)
{
Console.Writeline(result);
}
condition = true;
}
if (!condition)
{
// ..
}
}
Lazy
在多线程情况下很有用,或者你不完全确定是否/何时使用它。在您的情况下,您确实知道是否在该方法的范围内使用它,因此使用Lazy
只会使事情变得复杂。
是的,Lazy
适合这种情况。您的示例代码原则上是好的。它有一个问题,它使用.Result
而不是await
。但那只是一个细节,与本次讨论无关。
如果你想避免在这里使用Lazy
,让我建议一个替代方案:
string slowResult;
if (IsTrue(someValue) && (slowResult = await SuperSlowThing()).Length > 0)
{
Console.WriteLine(slowResult);
}
注意,您可以多次访问slowResult
而无需重新执行SuperSlowThing
。这就是你使用Lazy
的目的。
c# 6甚至允许你声明一个内联变量:
if (IsTrue(someValue) && (var slowResult = await SuperSlowThing()).Length > 0)
(至少我是这么认为的)
如果您发现嵌套赋值令人困惑(这是可以理解的):
if (IsTrue(someValue))
{
string slowResult = await SuperSlowThing();
if (slowResult.Length > 0)
Console.WriteLine(slowResult);
}
由于等待,这个问题实际上与同步代码中的问题相同。这不是关于异步或任务。写await SuperSlowThingAsync()
还是SuperSlowThing
对方法的逻辑流程没有影响。忽略思维中的异步性
如果是,有没有更简单的方法?
你的解决方案究竟实现了什么,一个简单的if
构造不能?
var syncResult = this.IsTrue(someValue);
if (syncResult)
{
var result = this.SuperSlowThing();
Console.WriteLine("Did SuperSlowThing - result is " + result);
}
else
{
Console.WriteLine("Didn't do SuperSlowThing");
}
如果您的目标是封装一个按需异步检索的值,那么Lazy<Task<T>>
是一个合适的抽象。从你的问题中很难判断这是否是你真正想要的。
考虑这两个:
var x = new Lazy<int>(
() => Task.Run(
() => ComputeValue()));
var y = Task.Run(
() => ComputeValue());
其中ComputeValue
是一个昂贵的函数,返回一个int
。
则分配给y
的值将立即开始计算。每个等待y
的人都在等待一个已经启动的Task
。
分配给x
的值只会在第一次有人请求该值时才开始计算,但是每个人在开始计算后仍然会等待相同的计算
Lazy
与同步或异步无关,它与延迟执行有关。在你的情况下,你根本没有推迟执行。您正在创建Lazy参数,然后立即访问它(假设您的值为true)。只要输入
if(condition)
{
var = await SuperSlowThing()
}