C# 异步 this.BeginInvoke 、`Task.Run` 或 `Thread`

需要更新UI,则用 this.BeginInvoke

this.BeginInvoke(new Action(() =>
{
    GetUserList();
}));

不需要更新UI,则可以用异步线程

Task.Run(() => GetUserList(););

1. 外部代码本身就在 UI 线程中运行

  • 如果你在 UI 线程中调用 this.BeginInvoke,那么 BeginInvoke 会将委托放入 UI 线程的消息队列中,但由于当前已经是 UI 线程,BeginInvoke 的委托仍然会在 UI 线程中执行。
  • 因此,外部代码和 GetUserList() 的线程 ID 会相同。

验证方法:
检查外部代码是否在 UI 线程中运行。例如:

Console.WriteLine("外部代码是否在 UI 线程中: " + this.InvokeRequired);
  • 如果 InvokeRequiredfalse,说明当前代码已经在 UI 线程中运行。

2. BeginInvoke 的行为

  • BeginInvoke 是异步的,但它仍然会将委托调度到 UI 线程中执行。
  • 如果外部代码已经在 UI 线程中运行,BeginInvoke 的委托会立即执行(或稍后执行,取决于消息队列的状态),但仍然在同一个线程中。

3. 代码执行顺序

  • 如果外部代码和 BeginInvoke 的委托都在 UI 线程中运行,它们的线程 ID 会相同。
  • 即使 BeginInvoke 是异步的,它仍然会在 UI 线程中执行,因此线程 ID 不会改变。

如何验证 BeginInvoke 的异步行为?

如果你想验证 BeginInvoke 的异步行为,可以尝试以下方法:

示例代码:

using System;
using System.Threading;
using System.Windows.Forms;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, EventArgs e)
    {
        // 打印外部代码的线程 ID
        Console.WriteLine("外部线程 ID: " + Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine("外部代码是否在 UI 线程中: " + this.InvokeRequired);

        // 使用 BeginInvoke 异步执行
        this.BeginInvoke(new Action(() =>
        {
            // 打印 GetUserList 的线程 ID
            Console.WriteLine("GetUserList 线程 ID: " + Thread.CurrentThread.ManagedThreadId);
            GetUserList();
        }));

        // 模拟外部代码继续执行
        Console.WriteLine("外部代码继续执行...");
    }

    private void GetUserList()
    {
        // 模拟方法执行
        Console.WriteLine("GetUserList 正在执行...");
    }
}

可能的输出:

如果外部代码在 UI 线程中运行,输出可能如下:

外部线程 ID: 1
外部代码是否在 UI 线程中: False
外部代码继续执行...
GetUserList 线程 ID: 1
GetUserList 正在执行...

如果外部代码在非 UI 线程中运行,输出可能如下:

外部线程 ID: 10
外部代码是否在 UI 线程中: True
外部代码继续执行...
GetUserList 线程 ID: 1
GetUserList 正在执行...

总结:

  • 如果外部代码和 GetUserList() 的线程 ID 相同,说明它们运行在同一个线程中(通常是 UI 线程)。
  • 如果你想验证 BeginInvoke 的异步行为,可以确保外部代码在非 UI 线程中运行(例如使用 Task.RunThread)。
  • 使用 InvokeRequired 可以检查当前代码是否在 UI 线程中运行。

如果你希望 GetUserList() 在另一个线程中运行,而不是在 UI 线程中,可以考虑使用 Task.Run 或其他多线程技术。例如:

Task.Run(() => GetUserList());
posted @ 2025-03-01 11:47  VipSoft  阅读(185)  评论(0)    收藏  举报