C#的耗时程序不卡UI线程

 

结合 C# 场景:

类型谁等结果?线程是否挂起?举例
同步阻塞 调用方主动等 ✅ 是(线程卡住) Thread.Sleep(5000) 在 UI 线程
同步非阻塞 调用方主动轮询 ❌ 否(但要不断检查) 手动 while (!task.IsCompleted) { DoOther(); }
异步阻塞 系统通知你,但你仍用 .Wait() 去等 ✅ 是(看似异步实则阻塞) task.Wait() 或 task.Result
异步非阻塞 系统通知你,你用回调或 await 继续 ❌ 否(线程释放) await Task.Run(...)

await Task.Run(() => {
    Thread.Sleep(5000); // 耗时操作
});
label1.Text = "完成";

“同步非阻塞”在 C# 里长这样,不推荐

// 同步非阻塞(反面教材)
var task = Task.Run(() => HeavyWork());
while (!task.IsCompleted)
{
    Application.DoEvents(); // 强行让 UI 刷新(WinForms 黑科技)
    Thread.Sleep(10);       // 小睡一下避免 CPU 爆炸
}
label1.Text = "完成";

 

若在执行耗时任务时,使用异步非阻塞,执行完后还想把执行后的状态结果,更新到UI界面上(其他线程)

方法一:获得UI线程上下文,给耗时方法传进去(或设置成全局变量),在耗时方法执行后改界面值。

    public partial class Form1 : Form
    {
        SynchronizationContext _uiContext;//UI界面上下文内容
        public Form1()
        {
            InitializeComponent();
            _uiContext = SynchronizationContext.Current;
        }
        private void btn_b1_Click(object sender, EventArgs e)
        {
            Task.Run(() => { this.test01(); }); 
        }
        //模拟耗时操作
        public void test01() {
            Thread.Sleep(5000);
            //btn_b1.Text = "OK";//报错
            _uiContext?.Post(_ => {
                // 安全检查!
                if (!IsDisposed && !Disposing) {btn_b1.Text = "ok";}
            }, null);
        }
    }

 

    public partial class Form1 : Form
    {
        SynchronizationContext _uiContext;
        public Form1()
        {
            InitializeComponent();
            _uiContext = SynchronizationContext.Current;//UI界面上下文内容
        }
        private void btn_b1_Click(object sender, EventArgs e)
        {
            _uiContext = SynchronizationContext.Current;
            Task.Run(() => {
                this.test01(_uiContext); 
            }); 
        }

        //模拟耗时操作
        public void test01(SynchronizationContext ctx) {
            Console.WriteLine("耗时操作开始....");
            Thread.Sleep(5000);
            Console.WriteLine("耗时操作结束....");
            //btn_b1.Text = "OK";//报错
            ctx?.Post(_ => {
                // 安全检查!
                if (!IsDisposed && !Disposing) {btn_b1.Text = "ok";}
            }, null);
        }
    }

 

方法二:用 IProgress<T> + Progress<T> 专门用于从后台任务向 UI 报告进度或状态!

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void btn_b1_Click(object sender, EventArgs e)
        {
            // 1. 创建 Progress 对象(在 UI 线程创建!)
            var progress = new Progress<string>(value =>
            {
                // 这个 lambda 会在 UI 线程执行!安全更新控件
                btn_b1.Text = value;
            });

            Task.Run(() => { this.test01(progress); });            
        }

        //模拟耗时操作
        public void test01(IProgress<string> progress) {
            Thread.Sleep(5000);
            //btn_b1.Text = "OK";//报错            
            progress?.Report($"OK");// 报告当前状态(线程安全!)
        }
    }

 

---------------------------------

例子,C# ,判断服务器80端口是否通畅,然后把结果更新到UI界面上。(两种方式,一种是true,false,结果更新到UI界面,另一种是各种信息更新到UI界面)

不对的写法:

{
            var progress = new Progress<string>(value =>{ lbl_network.Text = value;});
            Task.Run(() => {
                bool isAccessible = NetworkUtil.CheckPortAccessibility("a.cn", 80, 5000);
                if (isAccessible)
                {
                    //progress?.Report($"服务器正常链接.");//写法有错误,progress要作为参数传到上面耗时方法中,方法里面可以使用
                    lbl_network.Text = "服务器正常链接";//写法错误
                    Console.WriteLine($"服务器正常链接");
                }else{
                    //progress?.Report($"服务器断开中.....");
                    lbl_network.Text = "服务器正常链接";//写法错误
                    Console.WriteLine($"服务器断开中...");
                }
            });

}

 

改进后的写法:

   {         bool isAccessible = await Task.Run(() => {
                 return NetworkUtil.CheckPortAccessibility("a.cn", 80, 5000); 
            });
            if (isAccessible)
            {
                lbl_network.Text = "服务器正常链接.";//修改UI界面
                Console.WriteLine($"服务器正常链接");
            }  else  {
                lbl_network.Text = "服务器断开中....";//修改UI界面
                Console.WriteLine($"服务器断开中...");
            }
  }

 

另一种是各种状态更新到UI界面:那就是给耗时方法中传IProgress

            var progress = new Progress<string>(value =>{ lbl_network.Text = value;});
            Task.Run(() => {
                bool isAccessible = Bxlz.Common.NetworkUtil.CheckPortAccessibility("a.cn", 80, 5000, progress);
            });

然后给下面方法多加一个参数,最后方法里面使用  progress?.Report($"状态...");

 

 

判断服务器80端口的耗时方法:

        /// <summary>
        /// 检查指定主机和端口是否可访问
        /// </summary>
        /// <param name="host">目标主机</param>
        /// <param name="port">目标端口</param>
        /// <param name="timeoutMs">超时时间(毫秒)</param>
        /// <returns>是否可访问</returns>
        public static bool CheckPortAccessibility(string host, int port, int timeoutMs)
        {
            try
            {
                // 检查网络是否可用
                if (!NetworkInterface.GetIsNetworkAvailable())
                {
                    Console.WriteLine("网络不可用");
                    return false;
                }

                // 尝试解析DNS
                IPHostEntry hostEntry;
                try
                {
                    hostEntry = Dns.GetHostEntry(host);
                    Console.WriteLine($"DNS解析成功: {hostEntry.AddressList[0]}");
                }
                catch (SocketException se)
                {
                    Console.WriteLine($"DNS解析失败: {se.SocketErrorCode}");
                    return false;
                }

                // 尝试连接到服务器
                using (var client = new TcpClient())
                {
                    client.ReceiveTimeout = timeoutMs;
                    client.SendTimeout = timeoutMs;

                    // 使用异步连接
                    IAsyncResult result = client.BeginConnect(hostEntry.AddressList[0], port, null, null);

                    bool success = result.AsyncWaitHandle.WaitOne(timeoutMs, true);

                    if (success)
                    {
                        try
                        {
                            client.EndConnect(result);

                            if (client.Connected)
                            {
                                Console.WriteLine("TCP连接成功");

                                using (var stream = client.GetStream())
                                {
                                    // 发送HTTP HEAD请求
                                    string request = $"HEAD / HTTP/1.0\r\nHost: {host}\r\nConnection: close\r\n\r\n";
                                    byte[] requestData = Encoding.ASCII.GetBytes(request);

                                    stream.Write(requestData, 0, requestData.Length);
                                    Console.WriteLine("请求数据发送成功");

                                    // 尝试读取响应
                                    byte[] buffer = new byte[1024];
                                    try
                                    {
                                        IAsyncResult readResult = stream.BeginRead(buffer, 0, buffer.Length, null, null);

                                        if (readResult.AsyncWaitHandle.WaitOne(5000, true)) // 5秒读取超时
                                        {
                                            int bytesRead = stream.EndRead(readResult);
                                            if (bytesRead > 0)
                                            {
                                                string response = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                                                Console.WriteLine($"收到响应数据长度: {bytesRead} 字节");
                                                Console.WriteLine($"响应内容前100字符: {response.Substring(0, Math.Min(100, response.Length))}");

                                                // 检查是否是有效的HTTP响应
                                                if (response.StartsWith("HTTP/1.") && response.Contains("200"))
                                                {
                                                    Console.WriteLine("收到有效的HTTP响应");
                                                    return true;
                                                }
                                                else
                                                {
                                                    Console.WriteLine("收到非200状态的HTTP响应");
                                                    return false;
                                                }
                                            }
                                            else
                                            {
                                                Console.WriteLine("未收到任何响应数据");
                                                return false;
                                            }
                                        }
                                        else
                                        {
                                            Console.WriteLine("读取响应超时");
                                            return false;
                                        }
                                    }
                                    catch (Exception readEx)
                                    {
                                        Console.WriteLine($"读取响应时发生异常: {readEx.Message}");
                                        return false;
                                    }
                                }
                            }
                            else
                            {
                                Console.WriteLine("连接未建立");
                                return false;
                            }
                        }
                        catch (SocketException se)
                        {
                            Console.WriteLine($"结束连接时发生异常: {se.SocketErrorCode}");
                            return false;
                        }
                    }
                    else
                    {
                        Console.WriteLine("连接超时");
                        return false;
                    }
                }
            }
            catch (SocketException se)
            {
                Console.WriteLine($"Socket异常: {se.SocketErrorCode} - {se.Message}");
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"其他异常: {ex.Message}");
                return false;
            }
        }

 

posted @ 2025-12-05 10:28  与f  阅读(1)  评论(0)    收藏  举报