gpt4 book ai didi

c# - 使用事务的批量插入会阻止异步进程上的 UI

转载 作者:行者123 更新时间:2023-11-29 01:20:52 24 4
gpt4 key购买 nike

尝试使用异步/等待和事务将多条记录插入 MySQL 数据库,但它仍然导致 UI 在循环中变得卡住/无响应。

看看下面的代码,我做错了什么或者如何实现,以便 UI 在此过程中仍然响应。

异步方法

public static async Task AddRecords() {
foreach ( string month in Months ) {
await MakeTable( month );
string query="INSERT INTO `"+month+"` ( Caller, Started, Dialed, DurationSec, DurationMin, Cost, Location, Switch ) VALUES (@Caller, @Started, @Dialed, @DurationSec, @DurationMin, @Cost, @Location, @Switch);";
using ( MySqlConnection cn=new MySqlConnection( ConnectionString.ToString() ) ) {
await cn.OpenAsync();
using ( MySqlTransaction trans=cn.BeginTransaction() ) {
using ( MySqlCommand cmd=new MySqlCommand( query, cn, trans ) ) {
cmd.CommandType=CommandType.Text;
foreach ( Record r in CDR.Records ) {
if ( r.Started.ToString( "yyyy-MM" )==month ) {
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue( "@Caller", r.Caller );
cmd.Parameters.AddWithValue( "@Started", r.Started );
cmd.Parameters.AddWithValue( "@Dialed", r.Dialed );
cmd.Parameters.AddWithValue( "@DurationSec", r.Duration );
cmd.Parameters.AddWithValue( "@DurationMin", Math.Ceiling( r.Duration/60 ) );
cmd.Parameters.AddWithValue( "@Cost", r.Cost );
cmd.Parameters.AddWithValue( "@Location", r.Location );
cmd.Parameters.AddWithValue( "@Switch", r.Switch.ToString() );
cmd.ExecuteNonQuery();
}
}
trans.Commit();
}
}
await cn.CloseAsync();
}
}
}

有关如何调用它的片段:

    private async void button1_Click( object sender, EventArgs e ) {
this.Text = "Adding Records";
await AddRecords();
this.Text = "Completed";
}

顺便说一句,当 UI 阻塞时,它不应该在执行完所有先前代码后阻塞。例如,在上面的按钮点击方法中,第一个 'this.Text' 没有设置,因为一旦 await AddRecords(); 执行,它就发生在 UI 有机会完成更新之前,并且直到阻塞完成后才会完成,这导致只有 this.Text - "Completed" 在 UI 级别被注意到。


更新

cmd.ExecuteNonQuery(); 修改为 await cmd.ExecuteNonQueryAsync();(Yuval Itzchakov 推荐)后,UI 仍然阻塞,这让我相信了在 trans.Commit(); 行或与交易构建方式有关的事情上阻塞。

更新代码

public static async Task AddRecords() {
foreach ( string month in Months ) {
await MakeTable( month );
string query="INSERT INTO `"+month+"` ( Caller, Started, Dialed, DurationSec, DurationMin, Cost, Location, Switch ) VALUES (@Caller, @Started, @Dialed, @DurationSec, @DurationMin, @Cost, @Location, @Switch);";
using ( MySqlConnection cn=new MySqlConnection( ConnectionString.ToString() ) ) {
await cn.OpenAsync();
using ( MySqlTransaction trans=cn.BeginTransaction() ) {
using ( MySqlCommand cmd=new MySqlCommand( query, cn, trans ) ) {
cmd.CommandType=CommandType.Text;
foreach ( Record r in CDR.Records ) {
if ( r.Started.ToString( "yyyy-MM" )==month ) {
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue( "@Caller", r.Caller );
cmd.Parameters.AddWithValue( "@Started", r.Started );
cmd.Parameters.AddWithValue( "@Dialed", r.Dialed );
cmd.Parameters.AddWithValue( "@DurationSec", r.Duration );
cmd.Parameters.AddWithValue( "@DurationMin", Math.Ceiling( r.Duration/60 ) );
cmd.Parameters.AddWithValue( "@Cost", r.Cost );
cmd.Parameters.AddWithValue( "@Location", r.Location );
cmd.Parameters.AddWithValue( "@Switch", r.Switch.ToString() );
await cmd.ExecuteNonQueryAsync();
}
}
trans.Commit();
}
}
await cn.CloseAsync();
}
}
}

最佳答案

使用 ExecuteNonQueryAsync 而不是 ExecuteNonQuery:

await cmd.ExecuteNonQueryAsync();

这是查询中最耗时的调用,因为您使用的是同步版本,所以它被同步阻塞。

编辑:

因为你不需要做任何需要同步上下文的 UI 工作,你可以使用 ConfigureAwait(false),你可以将它应用到 OpenAsync,然后延续将在线程池 IO worker 上运行。

关于c# - 使用事务的批量插入会阻止异步进程上的 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31336162/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com