我有问题,使排行榜的不和谐机器人的迷你。
上下文:我有一个'users'的小集合,顾名思义,它包含系统用户的选择,由'User'对象表示。
我想获得这个集合中的前10个用户的'寿司'的数量,如果你愿意的话,一个分数。这个寿司是从一个数据库中单独提取的(不要担心性能,数据库是在SSD上,在同一个盒子上,这个代码将通过的用户集合是非常精简的)
IEnumerable<User> topUsers = users.OrderByDescending(async x => await FishEngine.GetItem(x, "sushi")).Take(10);
如果我是以非异步的方式来做这件事,按照本地存储在用户对象中的任何东西来排序,并且不需要等待,这会非常好地工作,但是当我这样做的时候,foreach中有一个异常,它表明集合topUsers不包含用户,而是似乎是任务的东西。
如果我在等待,为什么会发生这种情况?我应该怎么做才能解决这个问题?
先谢了。
PS,因为我知道有人会这样建议:我知道,在这一点上,通过SQL查询所有内容会更快,无论是作为一种解决方案,还是潜在的perf(尽管正如我在前面指出的,perf在这里不是一个现实的问题),但我真的希望了解我在异步lambda方面做错了什么。
编辑:因为请求了GetItem
public static async Task<int> GetItem(User dbUser, string name)
{
return await UserEngine._interface.FetchInventoryItem(dbUser, name);
}
不要担心会更深入,这个函数在其他地方也使用过,并且工作正常。
3条答案
按热度按时间jc3wubiy1#
诸如
OrderBy
之类的可枚举方法必须要么转换为SQL(作为查询的一部分),要么对内存中的数据进行操作。解决这个问题的最佳方法是将其转换为SQL,但由于您对另一种方法感兴趣,因此您可以 * 先 * 然后按顺序将所有值加载到内存中。您可以通过创建一个 * task * 序列,然后使用Task.WhenAll
来完成此操作:当然,这是非常低效的,因为您要单独加载每个用户的寿司,只是为了比较它们并在内存中取前10名。
mwg9r5ms2#
async x => await FishEngine.GetItem(x, "sushi")
几乎与x => FishEngine.GetItem(x, "sushi")
相同:await
是在异步方法中使用的,所以结果必须以某种方式等待以获得值。async
使你的lambda异步,也就是说,它返回Task<User>
,而不是你所期望的User
。Task<User>
在抽象的高层上等价于User
,但是它们是不可互换的。对于Task<int>
和int
也是如此:FishEngine.GetItem
不返回整数,而是(使用一点JS术语)承诺在以后某个时间点提供整数,因此您必须等待数据库引擎返回的承诺,以便每个用户都能够按寿司对用户进行排序。5vf7fwbs3#
由于
OrderByDescending
方法不支持异步lambda表达式,您提供的代码将无法按预期工作。要根据用户的“sushi”分数获得集合中的前10个用户,可以先使用
Task.WhenAll
并行获取所有用户的“sushi”分数,然后使用OrderByDescending
方法根据用户的“sushi”分数对用户进行排序。最后,使用Take
方法获得前10个用户。下面是一个示例:此脚本将使用
Task.WhenAll
方法并行获取所有用户的寿司得分,然后根据获得的寿司得分对用户进行排序,最后选择前10名用户。请记住,
Task.WhenAll
将等待所有任务完成后再继续,这意味着它将并行执行对数据库的所有调用,但将等待所有任务完成后再继续执行下一步。另外,需要注意的是,基于特定属性对大量项进行排序可能是一项性能密集型任务,如果用户集合非常大,则应考虑这一点。