由异步引起的死锁等待[MySQL数据库]

时间:2018-02-01 19:48:58

标签: c# mysql multithreading entity-framework async-await

我有以下异步方法删除并将记录插入MySQL数据库

public async Task<Res> myNewFunc(int id, IEnumerable<Sample> obs)
{      
    using (var t = DbConnection.GetTransaction())
    {
        await DbConnection.DeleteMany<M1>().Where(x.Id == id).ExecuteAsync();
        foreach (var ob in obs)
        {
            await DbConnection.InsertAsync(ob);
        }
        t.Complete();
    }
}

调用myNewFunc()的方法:

public async Task<T> method()
{
    //...
    //...
    var response = await DAL.myNewFunc(id, obs);
}

使用foreach循环访问异步方法。

foreach(var num in nums)
{
    method();
}

我使用上面的代码遇到MySQL的死锁问题。

1 个答案:

答案 0 :(得分:-1)

因为您没有在最后一个for循环中等待,所以它将为所有这些循环启动线程并同时并行运行所有这些线程。如果你在这里有很多数据,那么他们都将争夺相同的资源。您最终会在每种情况下创建事务,然后从表中删除多个记录。但是,这可能不是真正的潜在问题。在所有ExecuteAsync调用中,您不执行.ConfigureAwait(false)。这意味着在运行每个语句之后,它会一直等到它可以在原始线程(在本例中为UI线程)上恢复其工作。我不知道你在for循环之后做了什么,但是这个线程可能永远不会放弃,所以这些db调用都不会再回来,你会遇到死锁。

您可以尝试解决此问题的两种方法:

  1. 每个Async()调用都需要是Async()。ConfigureAwait(false)。如果真的是UI线程被锁定,这可能会解决它。

  2. 在最后一个for循环中,您需要等待每个循环,因为可能数据库资源全部被绑定了。请改用此代码:

  3. SparkConf conf = new SparkConf()
                            .setAppName("appName")
                            .setMaster("local");
    
           SparkSession sparkSession = SparkSession
                                       .builder()
                                       .config(conf)
                                      .getOrCreate();
            return sparkSession;
    

    这将一次只处理一个。对于#2,你可能也需要做#1。