2012-06-14 57 views
0

我做了一個加載一堆計算機信息的程序。在Form_Load事件中,我將它初始化爲3(該數字將增長)信息面板。有一堆單元信息似乎會使程序加載得相當緩慢。我試圖通過從WMI切換到使用Native調用來加速它,這幫助了一大堆。不久,我也會發佈網絡信息。我曾經加載該面板,但我禁用它一點點,直到我找出我的其他面板中的錯誤。因此,在瞭解如何使用單獨的線程更新電池信息時,我認爲我可以在單元信息面板中創建單獨的線程,以便加載速度更快。我不知道我的任何信息會導致併發問題,但我可以在這方面努力。多線程加速加載時間

我想開始小,所以如果我改變一下這個

private void Form1_Load(object sender, EventArgs e) 
    { 
     unitInformationPanel1.PopulateUnitInformation(); 
     batteryInformationPanel1.InitializeBatteries(); 
     magStripeReaderPanel1.SetupPointOfSale(); 
    } 

這個

private void Form1_Load(object sender, EventArgs e) 
    { 
     Thread infoThread = new Thread(new ThreadStart(unitInformationPanel1.PopulateUnitInformation)); 
     infoThread.Start(); 
     batteryInformationPanel1.InitializeBatteries(); 
     magStripeReaderPanel1.SetupPointOfSale(); 
    } 

會時填入單元信息完成的信息線程被終止?或者將該線程創建移動到PopulateUnitInformation更好?這是它的樣子。

public void PopulateUnitInformation() 
    { 
     unitModelLabel.Text = Properties.Settings.Default.UnitModelString; 
     serialNumberLabel.Text = Properties.Settings.Default.UnitSerialString; 
     biosVersionLabel.Text = UnitBios.GetBiosNumber(); 
     osLabel.Text = OS.getOSString(); 
     cpuLabel.Text = UnitCpu.GetCpuInfo(); 

     var hdd = HddInfo.GetHddInfo(); 
     diskNameLabel.Text = hdd.Name; 
     diskCapacityLabel.Text = hdd.Capacity; 
     diskFirmwareLabel.Text = hdd.Firmware; 
     memoryLabel.Text = MemoryInformation.GetTotalMemory(); 
     NetworkPresenceInformation.GetAdapatersPresent(); 
     biometricLabel.Text = BiometricInformation.IsPresent ? "Present" : "Not Present"; 
     var networkAdaptersPresense = NetworkPresenceInformation.GetAdapatersPresent(); 
     bluetoothLabel.Text = networkAdaptersPresense[0] ? "Present" : "Not Present"; 
     wifiLabel.Text = networkAdaptersPresense[1] ? "Present" : "Not Present"; 
     cellularLabel.Text = networkAdaptersPresense[2] ? "Present" : "Not Present"; 
    } 

-

哇,我剛剛與infothread運行它,它仍然花了一些時間來加載(可能是12個板我在主線程創建的,但它裝載的12幀和單位信息面板填充一切後,其信息加載,這是很酷,但它安全嗎?是不是有點容易使12個線程對我的面板?或者是啞巴?

編輯

這個我這是我爲秒錶做的。

Stopwatch programTimer; 
    public Form1() 
    { 
     programTimer = Stopwatch.StartNew(); 
     InitializeComponent(); 
     SetupDebugWindow(); 
     TerminateKeymon(); 
     UnitModel.SetModel(); 
     UnitSerialNumber.SetSerialNumber(); 
    } 
    private void Form1_Shown(object sender, EventArgs e) 
    { 
     audioBrightnessPanel1.UpdateBrightnessTrackbar(); 
     applicationLauncherPanel1.LoadApplications(); 
     programTimer.Stop(); 
     Console.WriteLine("Load Time: {0}",programTimer.ElapsedMilliseconds); 
     timer1.Start(); 
    } 

這將是準確的?

EDIT 2 2012年6月18日

嗯,我花了使用的BackgroundWorker的意見。請讓我知道,如果我這樣做的權利。

private void Form1_Load(object sender, EventArgs e) 
    { 
     backgroundWorker1.RunWorkerAsync(); 
    } 
    void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 
    { 
     unitInformationPanel1.PopulateUnitInformation(); 
     batteryInformationPanel1.InitializeBatteries(); 
     magStripeReaderPanel1.SetupPointOfSale(); 
    } 
+0

也有一種方法來計時嗎? –

+0

你正在說電池。這是用於移動設備(Win Phone,Android等)還是PC /筆記本電腦?個人電腦有一個[BackgroundWorker](http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx),這將是偉大的。 – jp2code

+0

@ jp2code PC平板電腦。 –

回答

2

所以我最後的辦法,這是如下。我覺得我的主要表格比應該做得更多。堅持單一職責原則,我決定MainForm只負責一件事,展示並顯示所有12個面板(現在降至11個,我將其中一個變爲菜單項)。所以將所有多線程移出mainform並放入program.cs。我發現這更加困難。我發現的雖然是一個簡單的解決方案,可以讓我甚至不用擔心多線程問題。這是空閒事件。這是我選擇做的事。

 [STAThread] 
    static void Main() 
    { 
     DateTime current = DateTime.Now; 
     DateTime today = new DateTime(2012,7,19); 
     TimeSpan span = current.Subtract(today); 
     if (span.Days<0) 
     { 
      MessageBox.Show("Please adjust Time then restart Aspects","Adjust Time"); 
      Process.Start("timedate.cpl").WaitForExit(); 
     } 
     else 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Idle += new EventHandler(Application_Idle); 

      mainForm = new MainForm(); 
      mainForm.Closing += new CancelEventHandler(mainForm_Closing); 

      #if !DEBUG 
      TerminateKeymon(); 
      StartSerial(); 
      SetupDefaultValues(); 
      EmbeddedMessageBox(0); 
      #endif 

      Application.Run(mainForm); 
     } 
    } 

    static void Application_Idle(object sender, EventArgs e) 
    { 
     Application.Idle -= Application_Idle; 
     mainForm.toolStripProgressBar1.Increment(1); 
     UnitInformation.SetupUnitInformation(); 
     mainForm.toolStripProgressBar1.Increment(1); 
     Aspects.Unit.HddInfo.GetHddInfo(); 
     mainForm.toolStripProgressBar1.Increment(1); 

     for (int i = 0; i < mainForm.Controls.Count; i++) 
     { 
      if (mainForm.Controls[i] is AbstractSuperPanel) 
      { 
       try 
       { 
        var startMe = mainForm.Controls[i] as AbstractSuperPanel; 
        startMe.StartWorking(); 
        mainForm.toolStripProgressBar1.Increment(1); 
       } 
       catch (Exception ex) 
       { 
        MessageBox.Show(ex.Message + mainForm.Controls[i].ToString()); 
       } 
      } 
     } 
     mainForm.toolStripProgressBar1.Value = 0; 
    } 

總結一下,我所做的是添加一個空閒偵聽器事件。一旦主機閒置(基本上意味着Mainform已完成繪圖並製作全部12個面板並顯示在桌面上),然後殺掉閒置事件偵聽器,並告訴我的所有面板和類一次開始工作,更新進度酒吧,因爲我去。它效果很好。加載時間仍然與以前相同,但只有幾秒鐘後纔有可見的窗口。也許不是資源的最佳利用方式,但我認爲解決方案簡單而直接。

7

您已經提出了一個非常廣泛的問題,但我會提供一些一般性建議。如果你想要更具體的信息,你應該考慮刪除這個問題併發布更多具體的個人問題。

  1. 首先,你應該非常認真考慮使用類似的System.Threading.Task類的多線程操作。網上有大量關於如何開始使用它的信息,以及如何使用Task來管理異步操作。簡短的故事是,如果你正在旋轉自己的線程(就像你上面做的那樣),那麼當你肯定應該使用別的東西來爲你做。

  2. 將多線程添加到您的代碼中,從最嚴格的意義上講,它不會使其「更快」;他們總是會花費相同數量的總處理器時間。它能做什麼和做什麼是兩件事:釋放UI線程以響應,並允許您將多個內核或處理器上的「總處理器時間」分開,如果這些時間可用於系統。所以,如果你有X操作需要10秒才能完成,那麼只要將X操作轉移到另一個線程上就不會超過10秒。

  3. 不,你上面做的是不是安全。我假設你關掉了在你的應用程序中檢查跨線程通信錯誤的地方?否則,假設這是一個WinForms或WPF應用程序,該代碼應該會引發異常。這是使用Task的原因之一,因爲您可以輕鬆分離實際需要很長時間(或與UI無關)的流程部分,然後添加使用結果的任務延續並將UI元素填充到正確同步的情況。

+0

謝謝你的信息。我現在將使用它,並看看它做了什麼。 –

+0

其實我沒有關閉我的程序中的任何跨線程通信。這只是一個標準的Winforms應用程序。我仍會研究任務。我的一個變化,雖然削減加載時間從7秒到3.5秒(根據我發佈的測試)。但我敢打賭,你的建議我可以把它降得更低。再次感謝您的提示。當我把它和工作,它會幫助我將你的答案標記爲答案。 –

+0

任務適用於版本4,我的部隊只有.net 3.5。所以我將不得不嘗試其他相關的東西 –

1

我有些與此相關的移動應用程序開發在幾個月前(見How to write a Trigger?)問題,和馬克「的哥」 Gravell回發一個簡單的類,我修改將數據返回給我的主應用程序只要線程完成。

實際的I類投入使用具有無意義的數據負載(你),所以我會在使用,我用來做技術Gravell先生的代碼的修訂版貼他們的工作:

首先,我要創建我自己的EventArgs類:

public class SuperEventArgs : EventArgs { 

    private object data; 

    public SuperEventArgs(object data) : base() { 
    this.data = data; 
    } 

    public object Data { get { return data; } } 

} 

利用這一點,這裏是我創建通過我的數據傳回主線程類:

public delegate event DataChangedHandler(object sender, SuperEventArgs e); 

public class Simple1 { 

    private object parameter1, parameter2; 
    private Control parent; 

    #if PocketPC 
    public delegate void MethodInvoker(); // include this if it is not defined 
    #endif 

    public Simple1(Control frmControl, object param1, object param2) { 
    parent = frmControl; 
    parameter1 = param1; 
    parameter2 = param2; 
    } 

    public event DataChangedHandler DataChanged; 

    public void Start() { 
    object myData = new object(); // whatever this is. DataTable? 
    try { 
     // long routine code goes here 
    } finally { 
     if (DataChanged != null) { 
     SuperEventArgs e = new SuperEventArgs(myData); 
     MethodInvoker methInvoker = delegate { 
      DataChanged(this, e); 
     }; 
     try { 
      parent.BeginInvoke(methInvoker); 
     } catch (Exception err) { 
      Log(err); // something you'd write 
     } 
     } 
    } 
    } 

} 

回到實際的執行主線,你會這樣做:

public partial class Form1 : Form { 

    private Simple1 simple; 

    public Form1() { 
    object query = new object(); // something you want to pass in 
    simple = new Simple1(this, query, DateTime.Now); 
    simple.DataChanged += new DataChangedHandler(simple1_DataChanged); 
    Thread thread = new Thread(simpleStart); 
    thread.Start(); 
    } 

    private void simpleStart() { 
    if (simple != null) { 
     simple.Start(); 
    } 
    } 

    private void simple1_DataChanged(object sender, SuperEventArgs e) { 
    MyFancyData fancy = e.Data as MyFancyData; 
    if (fancy != null) { 
     // populate your form with the data you received. 
    } 
    } 
} 

我知道它看起來很長,但它工作得很好!

這不是我實際測試過的任何東西,當然,因爲沒有任何數據。如果您需要使用它並且遇到任何問題,請告訴我,我會很樂意幫您解決問題。

〜的Joep