【问题标题】:Slow UI performance when searching database, despite threading尽管有线程,但搜索数据库时 UI 性能缓慢
【发布时间】:2016-02-17 00:00:38
【问题描述】:

我目前正在处理我的项目,而我一直面临的问题是当您在数据库中搜索数据时,性能会变慢并且没有响应。

我已经创建了一个线程,但它仍然让我头疼

//to start the thread when textbox has change
private void textBox1_TextChanged(object sender, EventArgs e)
{
    ThreadStart thread2Start = new ThreadStart(searchMyData);
    Thread t2 = new Thread(thread2Start);
    t2.Start();
}

public void searchMyData()
{
    if (radGridView1.InvokeRequired)
    {
        radGridView1.Invoke(new Action(() =>
        {
            MySqlConnection connection = new MySqlConnection(MyConnectionString);
            MySqlCommand cmd;
            connection.Open();

            try
            {
                if(!(textBox1.Text=="Search Students")) 
                { 
                    cmd = connection.CreateCommand();
                    cmd.CommandText = "SELECT * from studenttable where studname like'" + textBox1.Text + "%' OR studnum like'" + textBox1.Text + "%' OR studcourse like'" + textBox1.Text + "%' OR studemail like'" + textBox1.Text + "%' OR studsec like'" + textBox1.Text + "%' OR studgender like'" + textBox1.Text + "%' ";

                    MySqlDataAdapter adap = new MySqlDataAdapter(cmd);
                    DataSet ds = new DataSet();
                    adap.Fill(ds);
                    radGridView1.DataSource = ds.Tables[0].DefaultView;
                    connection.Close();
                }
            }
        }
    }
}

那么这里有什么解决方案可以提高我的程序的性能?

【问题讨论】:

标签: c# database multithreading


【解决方案1】:

您正在 UI 线程中运行 searchMyData() 函数,这就是它缓慢的原因。尝试更新以下代码,

private void txtSearch_TextChanged(object sender, EventArgs e)
{
    if (txtSymbol.Text == "Search Students")
    {
        ParameterizedThreadStart pts = new ParameterizedThreadStart(searchMyData);
        Thread t = new Thread(pts);
        t.Start(txtSymbol.Text);
    }
 }

public void searchMyData(object state)
{
    try
    {
        string text = state.ToString();
        using (MySqlConnection connection = new MySqlConnection(MyConnectionString))
        {
            connection.Open();
            MySqlCommand cmd = connection.CreateCommand();
            cmd.CommandText = "SELECT * from studenttable where studname like'" + text + "%' OR studnum like'" + text + "%' OR studcourse like'" + text + "%' OR studemail like'" + text + "%' OR studsec like'" + text + "%' OR studgender like'" + text + "%' ";

            MySqlDataAdapter adap = new MySqlDataAdapter(cmd);
            DataSet ds = new DataSet();
            adap.Fill(ds);
            radGridView1.Invoke(new Action(() => { radGridView1.DataSource = ds }));
        }
    }
    catch(Exception ex) { }
}

【讨论】:

  • 是的,但是该线程正在通过 radGridView1.Invoke() 调用将调用编组回 UI 线程。让我贴一些代码,这样更清楚。
  • 这就是它慢的原因 我强烈反对!我怀疑特定线程会使执行的函数/方法变慢或变快(除非您正在处理优先级)。你实际上的意思是它阻塞了 UI 线程,然后它不能处理任何其他 ui 渲染......但这没有被定义为 slow
  • 我确实在问题中看到了...radGridView1.InvokeRequiredradGridView1.Invoke(new Action(() =>
  • 你怎么能确定没有其他控件必须渲染?最后,您正在 UI 线程中运行 searchMyData() 函数在技术上并不完全正确。 op 正在 ui 线程上运行 searchMyData 方法的(内部)主体,因为他将其封装到委托/Action 中。
  • 调用正在同步到 UI 线程,如果 UI 线程忙,它仍然会在完成它正在做的任何事情后到达它。尝试自己运行代码,它不会阻塞。
【解决方案2】:

没有必要为这种事情引入显式线程。此代码中需要时间的操作是打开数据库连接并填充数据集。您可以轻松地使用任务和 async/await 在后台执行此操作。我认为 MySql 连接和适配器没有异步方法,因此您可能必须将它们包装在任务中,如下所示:

private void txtSearch_TextChanged(object sender, EventArgs e)
    {
        if (txtSymbol.Text == "Search Students")
        {
           radGridView1.DataSource = await SearchMyDataAsync(txtSymbol.Text);
        }
    }

    async Task<DataSet> SearchMyDataAsync(object state)
    {
        try
        {
            using (MySqlConnection connection = new MySqlConnection(MyConnectionString))
            {
                await Task.Run(() => connection.Open()); //Or possibly connection.OpenAsync() if it exists...
                MySqlCommand cmd = connection.CreateCommand();
                cmd.CommandText = "SELECT * from studenttable where studname like'" + text + "%' OR studnum like'" +
                                  text + "%' OR studcourse like'" + text + "%' OR studemail like'" + text +
                                  "%' OR studsec like'" + text + "%' OR studgender like'" + text + "%' ";

                MySqlDataAdapter adap = new MySqlDataAdapter(cmd);
                DataSet ds = new DataSet();
                await Task.Run(adap.Fill(ds));
                return ds;
            }
        }
        catch (Exception ex)
        {
            throw;
        }
    }

另外,请注意,当您从 UI 事件启动异步操作时,无论使用何种技术,都应该考虑可重入性。这里有一些关于堆栈溢出的好信息,但基本上,当用户快速连续键入一些字母时,您可能希望避免一次执行多个数据库查询。更多信息在这里:Reentrancy in async/await?

【讨论】:

  • 为什么是 await Task.Run(() =&gt; connection.Open()); ?数据集的填充也是异步的吗?它已经在异步运行。这看起来像是“让它全部异步,因为我们可以”。
  • 为什么要让方法返回数据集,等待它,然后在原始的txtSearch_TextChanged eventhandler 方法中使用它?
  • 我不明白第一条评论。打开是非常同步的。我已经更改了代码以反映第二条评论
  • 关于第一条评论,让我这样说:你这样做有什么好处:await Task.Run(() =&gt; connection.Open());而不是这个:connection.Open();
  • 这个:await Task.Run(adap.Fill(fs)); 而不是这个:adap.Fill(fs); ?
猜你喜欢
  • 2018-07-09
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多