詳解C#如何解決程序卡頓的問(wèn)題(多線程初步學(xué)習(xí))
正文
不帶參數(shù)的多線程實(shí)現(xiàn)
第一步 建立控制臺(tái)應(yīng)用
第二步 引用System.Threading.Thread
using System.Threading;
在 C# 中,System.Threading.Thread 類用于線程的工作。它允許創(chuàng)建并訪問(wèn)多線程應(yīng)用程序中的單個(gè)線程。進(jìn)程中第一個(gè)被執(zhí)行的線程稱為主線程。
第三步:完成代碼
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace 多線程Test { class Program { static void Main(string[] args) { int num = 100; for (int i = 0; i < num; i++) { //無(wú)參的多線程 noParmaThread(); } } private static void StartThread() { Console.WriteLine("------開(kāi)始了新線程------"); Thread.Sleep(2000);//wait Console.WriteLine("------線程結(jié)束------"); } /// <summary> ///不需要傳遞參數(shù) /// </summary> private static void noParmaThread() { ThreadStart threadStart = new ThreadStart(StartThread); var thread = new Thread(threadStart); thread.Start();//開(kāi)始線程 } } }
運(yùn)行結(jié)果
拓展:C#多線程刷新界面卡死測(cè)試
背景
在上位機(jī)程序開(kāi)發(fā)過(guò)程中,不可避免的會(huì)用到多線程,如處理Socket通信、PLC讀取、界面數(shù)據(jù)實(shí)時(shí)刷新等。在某個(gè)項(xiàng)目中由于開(kāi)啟的線程很多,出現(xiàn)了不定期界面卡死狀況,但后臺(tái)線程還在運(yùn)行,日志還在輸出。為了解決這個(gè)問(wèn)題,特寫了模擬程序進(jìn)行問(wèn)題復(fù)現(xiàn)。順便把過(guò)程分享一下。
要點(diǎn)
1、區(qū)分Control.BeginInvoke和Control.Invoke的用法
2、區(qū)分System.Timers.Timer、System.Threading.ThreadPool、System.Threading.Thread
Demo
創(chuàng)建一個(gè)WinForm應(yīng)用程序,把工程屬性的輸出類型設(shè)置為控制臺(tái)應(yīng)用程序,方便運(yùn)行時(shí)查看日志。
關(guān)鍵代碼
BasicInvoker
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WinApp { /// <summary> /// 調(diào)用器 /// </summary> public class BasicInvoker { public delegate void Invoke(); private Form form = null; private TextBox txt = null; private object value = String.Empty; public BasicInvoker(Form form, TextBox txt, object value) { this.form = form; this.txt = txt; this.value = value; } public void SetValue() { if (this.form != null && !this.form.IsDisposed) { if (this.form.InvokeRequired) { Delegate d = new Invoke(this.DoWork); try { this.form.Invoke(d, null); //this.form.BeginInvoke(d); } catch(Exception ex) { Console.WriteLine(ex.Message); } } else { this.DoWork(); } } } public void DoWork() { if (this.txt != null) { this.txt.Text = this.value.ToString(); Console.WriteLine(String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now) + " " + this.value.ToString() + "...1"); System.Threading.Thread.Sleep(200); Console.WriteLine(String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now) + " " + this.value.ToString() + "...2"); } } } }
FrmTest
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WinApp { public partial class FrmTester : Form { #region 變量定義 private System.Timers.Timer timer1 = null; private System.Timers.Timer timer2 = null; private System.Timers.Timer timer3 = null; private System.Threading.Thread thread1 = null; private System.Threading.Thread thread2 = null; private System.Threading.Thread thread3 = null; #endregion #region 構(gòu)造方法 public FrmTester() { InitializeComponent(); } #endregion #region 事件處理 private void Form1_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { if (timer1 == null) { timer1 = new System.Timers.Timer(); timer1.Interval = 500; timer1.Elapsed += t1_Elapsed; timer1.Start(); } } private void button2_Click(object sender, EventArgs e) { if (timer2 == null) { timer2 = new System.Timers.Timer(); timer2.Interval = 500; timer2.Elapsed += t2_Elapsed; timer2.Start(); } } private void button3_Click(object sender, EventArgs e) { if (timer3 == null) { timer3 = new System.Timers.Timer(); timer3.Interval = 500; timer3.Elapsed += t3_Elapsed; timer3.Start(); } } private void button4_Click(object sender, EventArgs e) { System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack1)); } private void button5_Click(object sender, EventArgs e) { System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack2)); } private void button6_Click(object sender, EventArgs e) { System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack3)); } private void button7_Click(object sender, EventArgs e) { if (this.thread1 == null) { this.thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack1)); this.thread1.Start(); } } private void button8_Click(object sender, EventArgs e) { if (this.thread2 == null) { this.thread2 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack2)); this.thread2.Start(); } } private void button9_Click(object sender, EventArgs e) { if (this.thread3 == null) { this.thread3 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack3)); this.thread3.Start(); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { Console.WriteLine("FormClosing..."); if (this.timer1 != null) { this.timer1.Stop(); this.timer1.Dispose(); } if (this.timer2 != null) { this.timer2.Stop(); this.timer2.Dispose(); } if (this.timer3 != null) { this.timer3.Stop(); this.timer3.Dispose(); } if (this.thread1 != null) { //if (this.thread1.ThreadState == System.Threading.ThreadState.Running) { this.thread1.Abort(); } } if (this.thread2 != null) { //if (this.thread2.ThreadState == System.Threading.ThreadState.Running) { this.thread2.Abort(); } } if (this.thread3 != null) { //if (this.thread3.ThreadState == System.Threading.ThreadState.Running) { this.thread3.Abort(); } } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { Console.WriteLine("FormClosed..."); } #endregion #region 定時(shí)處理方法定義 private void t1_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //lock(Global.PublicVar.Instance.Locker1) lock (String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString()); invoker.SetValue(); } } private void t2_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { lock (Global.PublicVar.Instance.Locker1) lock (String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); invoker.SetValue(); } } private void t3_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //lock (Global.PublicVar.Instance.Locker1) lock (String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); invoker.SetValue(); } } public void CallBack1(object state) { while(true) { //lock (Global.PublicVar.Instance.Locker1) lock(String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString()); invoker.SetValue(); } System.Threading.Thread.Sleep(500); } } public void CallBack2(object state) { while (true) { //lock (Global.PublicVar.Instance.Locker1) lock(String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); invoker.SetValue(); } System.Threading.Thread.Sleep(500); } } public void CallBack3(object state) { while (true) { //lock (Global.PublicVar.Instance.Locker1) lock(String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); invoker.SetValue(); } System.Threading.Thread.Sleep(500); } } public void CallBack1() { while (true) { //lock (Global.PublicVar.Instance.Locker1) lock (String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString()); invoker.SetValue(); } System.Threading.Thread.Sleep(500); } } public void CallBack2() { while (true) { //lock (Global.PublicVar.Instance.Locker1) lock (String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); invoker.SetValue(); } System.Threading.Thread.Sleep(500); } } public void CallBack3() { while (true) { //lock (Global.PublicVar.Instance.Locker1) lock (String.Empty) { BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); invoker.SetValue(); } System.Threading.Thread.Sleep(500); } } #endregion } }
運(yùn)行圖:
運(yùn)行結(jié)果:
一、使用Control.BeginInvoke的情況
public void SetValue() { if (this.form != null && !this.form.IsDisposed) { if (this.form.InvokeRequired) { Delegate d = new Invoke(this.DoWork); try { //this.form.Invoke(d, null); this.form.BeginInvoke(d); } catch(Exception ex) { Console.WriteLine(ex.Message); } } else { this.DoWork(); } } }
1.1、System.Timers.Timer開(kāi)啟2以上很快界面卡死,日志正常輸出。
1.2、System.Threading.ThreadPool開(kāi)啟3個(gè)時(shí),運(yùn)行一會(huì)界面卡死,日志正常輸出。
1.3、System.Threading.Thread開(kāi)啟3個(gè)時(shí),運(yùn)行一會(huì)界面卡死,日志正常輸出。
二、使用Control.Invoke的情況
public void SetValue() { if (this.form != null && !this.form.IsDisposed) { if (this.form.InvokeRequired) { Delegate d = new Invoke(this.DoWork); try { this.form.Invoke(d, null); //this.form.BeginInvoke(d); } catch(Exception ex) { Console.WriteLine(ex.Message); } } else { this.DoWork(); } } }
2.1、System.Timers.Timer開(kāi)啟3個(gè)時(shí)很快界面卡死,日志正常輸出。
2.2、System.Threading.ThreadPool開(kāi)啟3個(gè)時(shí),界面正常操作,日志正常輸出。
2.3、System.Threading.Thread開(kāi)啟3個(gè)時(shí),界面正常操作,日志正常輸出。
測(cè)試總結(jié):
1、System.Threading.ThreadPool與System.Threading.Thread運(yùn)行效果基本相同。
2、在多線程刷新界面時(shí)盡量通過(guò)Control.Invoke調(diào)用委托實(shí)現(xiàn)。
小結(jié)
到此這篇關(guān)于詳解C#如何解決程序卡頓的問(wèn)題(多線程初步學(xué)習(xí))的文章就介紹到這了,更多相關(guān)C#解決程序卡頓內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C#中對(duì)于接口的實(shí)現(xiàn)方式(隱式接口和顯式接口)
這篇文章主要介紹了詳解C#中對(duì)于接口的實(shí)現(xiàn)方式(隱式接口和顯式接口),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12C#向PPT文檔插入圖片以及導(dǎo)出圖片的實(shí)例
PowerPoint演示文稿是我們?nèi)粘9ぷ髦谐S玫霓k公軟件之一,本篇文章介紹了C#向PPT文檔插入圖片以及導(dǎo)出圖片的實(shí)例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2016-12-12c# Winform同一數(shù)據(jù)源多個(gè)控件保持同步
通過(guò)對(duì)控件屬性設(shè)置數(shù)據(jù)源綁定,利用Windows數(shù)據(jù)更改通知這一特性,只要訂閱(設(shè)定綁定)的控件都能接收到數(shù)據(jù)的變化通知。 通過(guò)DataBindings方法實(shí)現(xiàn)雙向數(shù)據(jù)綁定2021-06-06