自学内容网 自学内容网

C# - 异步编程和同步编程总结

在Windows Forms或WPF等桌面应用中,Invoke 和 BeginInvoke 是用来在创建控件的UI线程上安全地执行代码的关键方法,主要是为了处理多线程环境下的UI交互。

  • Invoke: 它是一个同步操作。当你调用 Invoke 时,当前线程会被阻塞,直到UI线程执行完传递给它的委托(Lambda表达式或Delegate实例)。这种方式适用于需要保证执行顺序且不介意短暂阻塞当前线程的情况。

  • BeginInvoke: 另一方面,BeginInvoke 是一个异步操作。它将操作添加到UI线程的消息队列中并立即返回,不会等待执行完成。因此,当前线程不会被阻塞,可以继续执行后续代码。但是,由于非阻塞特性,BeginInvoke 不保证操作的执行顺序,如果有多个调用,它们可能会按照不同的顺序执行。在性能敏感或无序执行不影响逻辑的情况下,应优先考虑使用 BeginInvoke

异步编程

1.说明

var result = await Task.Run(() =>
{
    
});

2.举例 

var result = await Task.Run(() =>
{
    // 更新textBox1
    if (this.textBox1.InvokeRequired)
    {
        this.textBox1.BeginInvoke(new Action(() =>
        {
            this.textBox1.Text = "成品仓-" + name1;
        }));
    }
    else
    {
        this.textBox1.Text = "成品仓-" + name1;
    }

    // 更新verticalProgressBar1
    if (this.verticalProgressBar1.InvokeRequired)
    {
        this.verticalProgressBar1.BeginInvoke(new Action(() =>
        {
            this.verticalProgressBar1.Value = Convert.ToInt32(progress);
        }));
    }
    else
    {
        this.verticalProgressBar1.Value = Convert.ToInt32(progress);
    }

    // 更新label1
    if (this.label1.InvokeRequired)
    {
        this.label1.BeginInvoke(new Action(() =>
        {
            this.label1.Text = Convert.ToInt32(progress) + "%";
        }));
    }
    else
    {
        this.label1.Text = Convert.ToInt32(progress) + "%";
    }

    // 更新dataGridView2 DataSource
    if (this.dataGridView2.InvokeRequired)
    {
        this.dataGridView2.BeginInvoke(new Action(() =>
        {
            this.dataGridView2.DataSource = datatable2;
        }));
    }
    else
    {
        this.dataGridView2.DataSource = datatable2;
    }
});
 3.异步编程出现的问题
1.System.InvalidOperationException:“线程间操作无效: 从不是创建控件“”的线程访问它。”
 this.textBox1.BeginInvoke(new Action(() =>
 {
       
 }));
2.System.InvalidOperationException:“在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。”
if (this.textBox1.InvokeRequired)
{
    
}
else
{
    
}

2.同步编程 

Invoke(new Action(() => ... )) 

举例 

 Invoke(new Action(() =>
 {
     // 清空文本框等UI元素
     ClearUiElements();
 }));

总结来说,Invoke 适合需要保证顺序和同步的简单场景,而 BeginInvoke 更适用于复杂情况,当你希望保持当前线程的活跃,不关心执行顺序或能够处理潜在的并发问题时。 


原文地址:https://blog.csdn.net/caoyanchao1/article/details/140352719

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!