首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用异步并等待中断数据库调用(使用Dapper)

使用异步并等待中断数据库调用(使用Dapper)
EN

Stack Overflow用户
提问于 2014-07-04 11:05:52
回答 2查看 7.2K关注 0票数 10

我们请求从Dapper返回数千个对象,并达到参数限制(2100),因此决定将它们装入块中。

我想这将是一个尝试异步等待的好机会--这是我第一次尝试,所以也许是犯了一个错误!

断点被击中了,但整件事都没有回来。它没有抛出一个错误-它只是看起来一切都在一个黑洞!

救命啊!

这是我最初的方法--它现在调用异步方法。

代码语言:javascript
运行
复制
    public List<MyObject> Get(IEnumerable<int> ids)
    {
        return this.GetMyObjectsAsync(ids).Result.ToList();
    }  //Breakpoint on this final bracket never gets hit

我添加了这个方法来将ids分割成1000个块,然后等待任务完成。

代码语言:javascript
运行
复制
    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;
    }

下面是任务..。

代码语言:javascript
运行
复制
    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列表拆分成块--这看起来很好.

代码语言:javascript
运行
复制
    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;
        }
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-07-04 11:16:16

您使用async/awaitTask<T>.Result的方式创建了死锁情况。

冒犯的界限是:

代码语言:javascript
运行
复制
return this.GetMyObjectsAsync(ids).Result.ToList();

GetMyObjectsAsync(ids).Result阻塞当前同步上下文。但是GetMyObjectsAsync使用await来调度当前同步上下文的延续点。我相信您可以看到这种方法的问题:因为Task.Result阻止了当前的同步上下文,所以永远无法执行延续。

在某些情况下可以工作的一种解决方案是使用ConfigureAwait(false),这意味着可以在任何同步上下文上运行延续。

但总的来说,我认为最好避免使用Task.Resultasync/await

请注意,这种死锁情况是否实际发生取决于调用异步方法时使用的同步上下文。对于ASP.net、Windows和WPF,这将导致死锁,但据我所知,对于控制台应用程序来说不会。(感谢马克·格雷维尔的评论)

微软有一篇关于异步编程的最佳实践的好文章。(多亏了ken2k)

票数 13
EN

Stack Overflow用户

发布于 2014-07-04 11:39:12

我认为参数是区分大小写的,应该是:

代码语言:javascript
运行
复制
return await db.QueryAsync<MyObject>(@"SELECT Something FROM Somewhere WHERE ID IN @ids",
            new { ids});

下面查询的是“@ in”,而不是“@in”:

代码语言:javascript
运行
复制
 return await db.QueryAsync<MyObject>(@"SELECT Something FROM Somewhere WHERE ID IN **@Ids**",
            new { ids});

虽然不确定,但还是试试吧。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24572908

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档