我们请求从Dapper返回数千个对象,并达到参数限制(2100),因此决定将它们装入块中。
我想这将是一个尝试异步等待的好机会--这是我第一次尝试,所以也许是犯了一个错误!
断点被击中了,但整件事都没有回来。它没有抛出一个错误-它只是看起来一切都在一个黑洞!
救命啊!
这是我最初的方法--它现在调用异步方法。
public List<MyObject> Get(IEnumerable<int> ids)
{
return this.GetMyObjectsAsync(ids).Result.ToList();
} //Breakpoint on this final bracket never gets hit我添加了这个方法来将ids分割成1000个块,然后等待任务完成。
private async Task<List<MyObject>> GetMyObjectsAsync(IEnumerable<int> ids)
{
var subSets = this.Partition(ids, 1000);
var tasks = subSets.Select(set => GetMyObjectsTask(set.ToArray()));
//breakpoint on the line below gets hit ...
var multiLists = await Task.WhenAll(tasks);
//breakpoint on line below never gets hit ...
var list = new List<MyObject>();
foreach (var myobj in multiLists)
{
list.AddRange(myobj);
}
return list;
}下面是任务..。
private async Task<IEnumerable<MyObject>> GetMyObjectsTask(params int[] ids)
{
using (var db = new SqlConnection(this.connectionString))
{
//breakpoint on the line below gets hit
await db.OpenAsync();
return await db.QueryAsync<MyObject>(@"SELECT Something FROM Somewhere WHERE ID IN @Ids",
new { ids});
}
}下面的方法只是将ids列表拆分成块--这看起来很好.
private IEnumerable<IEnumerable<T>> Partition<T>(IEnumerable<T> source, int size)
{
var partition = new List<T>(size);
var counter = 0;
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
partition.Add(enumerator.Current);
counter++;
if (counter % size == 0)
{
yield return partition.ToList();
partition.Clear();
counter = 0;
}
}
if (counter != 0)
yield return partition;
}
}发布于 2014-07-04 11:16:16
您使用async/await和Task<T>.Result的方式创建了死锁情况。
冒犯的界限是:
return this.GetMyObjectsAsync(ids).Result.ToList();GetMyObjectsAsync(ids).Result阻塞当前同步上下文。但是GetMyObjectsAsync使用await来调度当前同步上下文的延续点。我相信您可以看到这种方法的问题:因为Task.Result阻止了当前的同步上下文,所以永远无法执行延续。
在某些情况下可以工作的一种解决方案是使用ConfigureAwait(false),这意味着可以在任何同步上下文上运行延续。
但总的来说,我认为最好避免使用Task.Result和async/await。
请注意,这种死锁情况是否实际发生取决于调用异步方法时使用的同步上下文。对于ASP.net、Windows和WPF,这将导致死锁,但据我所知,对于控制台应用程序来说不会。(感谢马克·格雷维尔的评论)
微软有一篇关于异步编程的最佳实践的好文章。(多亏了ken2k)
发布于 2014-07-04 11:39:12
我认为参数是区分大小写的,应该是:
return await db.QueryAsync<MyObject>(@"SELECT Something FROM Somewhere WHERE ID IN @ids",
new { ids});下面查询的是“@ in”,而不是“@in”:
return await db.QueryAsync<MyObject>(@"SELECT Something FROM Somewhere WHERE ID IN **@Ids**",
new { ids});虽然不确定,但还是试试吧。
https://stackoverflow.com/questions/24572908
复制相似问题