SQL执行

时间:2017-01-30 01:17:24

标签: c# multithreading winforms .net-4.5 backgroundworker

在我的C#WindowsForm应用程序中,我尝试使用固定的持续时间(在我的情况下为6500毫秒)从开始到结束为进度条设置动画。这大概是SQL Execute需要多长时间。

我已经尝试在执行SQL之前运行animate方法,但是当SQL正在执行时,它看起来像是整个线程被冻结了。我不想在异常的情况下异步运行SQL。

我是多线程和后台工作流程的新手,虽然我认为这可能是关键?

如果有人能指引我朝着正确的方向前进,我们将不胜感激!

private void btnInternalMovement_Click(object sender, EventArgs e)
{

    AnimateProgBar(6500);


    // ***** BLAH MORE CODE HERE ******

    using (SqlCommand cmd = new SqlCommand("CatamacInternalStockMovement_C", SqlConnection))
    {

        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@ItemName", items);
        cmd.Parameters.AddWithValue("@Quantity", quantities);
        cmd.Parameters.AddWithValue("@WarehouseFrom", cbxFromWarehouse.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@WarehouseTo", cbxToWarehouse.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@LocationFrom", cbxFromZone.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@LocationTo", cbxToZone.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@UOM", "Each");
        cmd.Parameters.AddWithValue("@TransferDate", DateTime.Now);
        cmd.Parameters.AddWithValue("@User", User);
        cmd.ExecuteNonQuery();

    }

    // PROGRESS BAR ONLY STARTS ANIMATING HERE
    MessageBox.Show("Success!");

}

这是timer / Animate方法的代码。

private void timer1_Tick(object sender, EventArgs e)
{
    if (progressBar1.Value < 100)
    {
        progressBar1.Value += 1;
        progressBar1.Refresh();
    }
    else
    {
        timer1.Enabled = false;
    }
}

public void AnimateProgBar(int milliSeconds)
{
    if (timer1.Enabled) return;

    progressBar1.Value = 0;
    timer1.Interval = milliSeconds / 100;
    timer1.Enabled = true;
}

2 个答案:

答案 0 :(得分:2)

因为cmd.ExecuteNonQuery();在回调到btnInternalMovement_Click内部执行,所以它在UI线程上执行。在完成任何回调所需的时间内,UI将被阻止,包括btnInternalMovement_Click。如果cmd.ExecuteNonQuery()需要很长时间才能完成,那么您会看到在UI中反映出冻结更新;没有响应的键盘和鼠标输入。

async / await with Network-bound Calls

您对数据库的调用是 I / O绑定而非 CPU绑定,因此您不应使用Task.Run()根据{{​​3}}。如果您想使用async/await,请确保使用IOCP表格,而不是在整个通话期间启动和/或浪费一致的工作线程

当有完美的Task.Run()时,请避免使用ExecuteNonQueryAsync()ExecuteNonQueryAsync()在构建时考虑了IOCP,并且比执行类似的操作更有效:

await Task.Run(() =>
   {
      // I/O-bound: bad!  DON'T DO THIS for I/O-bound operations such 
      //as disk; network; DB etc
   });

改变这个:

private void btnInternalMovement_Click(object sender, EventArgs e)
{

    AnimateProgBar(6500);


    // ***** BLAH MORE CODE HERE ******

    using (SqlCommand cmd = new SqlCommand("CatamacInternalStockMovement_C", SqlConnection))
    {

        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@ItemName", items);
        cmd.Parameters.AddWithValue("@Quantity", quantities);
        cmd.Parameters.AddWithValue("@WarehouseFrom", cbxFromWarehouse.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@WarehouseTo", cbxToWarehouse.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@LocationFrom", cbxFromZone.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@LocationTo", cbxToZone.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@UOM", "Each");
        cmd.Parameters.AddWithValue("@TransferDate", DateTime.Now);
        cmd.Parameters.AddWithValue("@User", User);
        cmd.ExecuteNonQuery();

    }

    // PROGRESS BAR ONLY STARTS ANIMATING HERE
    MessageBox.Show("Success!");

}

...为:

private async void btnInternalMovement_Click(object sender, EventArgs e)
{

    AnimateProgBar(6500);


    // ***** BLAH MORE CODE HERE ******

    using (SqlCommand cmd = new SqlCommand("CatamacInternalStockMovement_C", SqlConnection))
    {

        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@ItemName", items);
        cmd.Parameters.AddWithValue("@Quantity", quantities);
        cmd.Parameters.AddWithValue("@WarehouseFrom", cbxFromWarehouse.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@WarehouseTo", cbxToWarehouse.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@LocationFrom", cbxFromZone.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@LocationTo", cbxToZone.SelectedValue.ToString());
        cmd.Parameters.AddWithValue("@UOM", "Each");
        cmd.Parameters.AddWithValue("@TransferDate", DateTime.Now);
        cmd.Parameters.AddWithValue("@User", User);
        await cmd.ExecuteNonQueryAsync(); // <----- NEW

    }

    // PROGRESS BAR ONLY STARTS ANIMATING HERE
    MessageBox.Show("Success!");

}

另见

答案 1 :(得分:1)

您的代码中可能存在一些错误;

  1. 你似乎没有开始()你的计时器,它可能应该放在AnimateProgBar中。

  2. AnimateProgBar在它的参数中需要毫秒,但你这样做

    timer1.Interval = milliSeconds / 100;

  3. 这是错误的,因为.Interval也期望毫秒。

    要回答您的问题,您只需将btnInternalMovement_Click更改为

    即可
        private async void btnInternalMovement_Click(object sender, EventArgs e)
    {
    
        AnimateProgBar(6500);
    
    
        // ***** BLAH MORE CODE HERE ******
    await Task.Run(() => { 
        using (SqlCommand cmd = new SqlCommand("CatamacInternalStockMovement_C", SqlConnection))
        {
    
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@ItemName", items);
            cmd.Parameters.AddWithValue("@Quantity", quantities);
            cmd.Parameters.AddWithValue("@WarehouseFrom", cbxFromWarehouse.SelectedValue.ToString());
            cmd.Parameters.AddWithValue("@WarehouseTo", cbxToWarehouse.SelectedValue.ToString());
            cmd.Parameters.AddWithValue("@LocationFrom", cbxFromZone.SelectedValue.ToString());
            cmd.Parameters.AddWithValue("@LocationTo", cbxToZone.SelectedValue.ToString());
            cmd.Parameters.AddWithValue("@UOM", "Each");
            cmd.Parameters.AddWithValue("@TransferDate", DateTime.Now);
            cmd.Parameters.AddWithValue("@User", User);
            cmd.ExecuteNonQuery();
    
        }
    
        // PROGRESS BAR ONLY STARTS ANIMATING HERE
        MessageBox.Show("Success!");
    });
    }
    

    请注意,该方法现在标记为异步,并且长时间运行的东西位于Task.Run(将其置于后台)中。你真的不想在UI线程中发生长时间运行的任务。

    显然异步编程比我回答这个问题要多得多,所以请参阅https://msdn.microsoft.com/en-us/library/mt674882.aspx