簡體   English   中英

BackgroundWorker凍結了我的UI,BeginInvoke似乎加快了速度

[英]BackgroundWorker freezes my UI and BeginInvoke seems to go turtle speed

我必須做一個看似很簡單的任務:1)列出目錄(及其子目錄)中的所有文件,2)在多行文本框中顯示所有文件,然后3)在每個文件中執行一些操作。 由於2個問題,我被困在2)中,這是我的問題:

  1. Form1.cs是我管理UI並啟動運行Logic.cs主要功能的BackgroundWorkerLogic.cs
  2. DependencyMapper.cs是...好,我在其中處理文件夾/文件(在Fetch() )並調用Form1方法,該方法使用BeginInvoke將每一行(當前文件的名稱)填充到Form1's文本框中。

少說話,多代碼。 這是我的代碼的皮包骨頭,可以正常使用的版本:

Form1.cs

public partial class Form1 : Form
{
    public DependencyMapper dep;
    BackgroundWorker bwDep;

    public Form1()
    {
        // I read here in SO to try put the BW stuff here don't know why, but hasn't helped.
        InitializeComponent();

        bwDep = new BackgroundWorker();
        bwDep.DoWork += bwDep_DoWork;
        bwDep.RunWorkerCompleted += bwDep_RunWorkerCompleted;
    }

    private void button1_Click(object sender, EventArgs e)
    {
            bwDep.RunWorkerAsync();
    }
    void bwDep_DoWork(object sender, DoWorkEventArgs e)
    {
        dep.Fetch(extensions);
    }
    public void SendBack(string msg) // To receive Fetch()s progress
    {
        textBox2.BeginInvoke(new Action(() =>
        {
            textBox2.Text += msg + "\r\n";
            textBox2.SelectionStart = textBox2.Text.Length;
            textBox2.ScrollToCaret();
        }));
    }
}

DependencyMapper.cs

public class DependencyMapper
{
    private Form1 form;
    public DependencyMapper(Form1 form1)
    {
        this.form = form1;
    }
    public void Fetch()
    {
        DirectoryInfo folder = new DirectoryInfo(form.Texto1);
        FileInfo[] files = folder.GetFiles("*.*", SearchOption.AllDirectories);
        for (int i = 0; i < files.Length; i++)
        {
            form.SendBack(files[i].FullName); // Kind of talking back to the UI through form's reference and SendBack method which uses BeginInvoke.
        }
    }
}

那么,我的應用程序正常工作嗎? 是的,但是我無法解決兩個巨大的問題:

  1. 它凍結UI(wtf懶惰BackgroundWorker嗎?)。 並非完全如此,因為文本框是一個一個地添加每個文件,但是就像應該的那樣,但是我無法在窗口中四處移動或單擊任何按鈕。
  2. 慢點。 肯定我做錯了。 我的應用程序當前以每秒大約10個文件的速度填充文本框。 我正在對其進行編碼,以在數百個文件中查找特定的文本片段... omg

PS:在使用BackgroundWorker之前,我使用的是Thread :UI完全沒有凍結,但是文本框的填充速度很慢。 這就是為什么我決定與BackgroundWorker一起冒險,這只會帶來問題#1。

謝謝。

消防沖水 UI線程,產生的結果遠遠超過了更快的用戶界面可以顯示它們。 它可能起步不錯,但隨着時間的流逝會越來越糟。 您強制TextBox重新分配內存以查找附加字符串的空間,復制原始文本並附加新文本。 一旦文本框包含兆字節的文本(贈送或接受),這將嚴重開始拖累。 System.String類具有相同的問題。 它具有StringBuilder作為修復程序,而TextBox沒有任何相似之處。

通常的症狀是UI線程將開始刻錄100%的內核。 在某個關鍵時刻,它完全崩潰了,不再重繪UI並對輸入無響應。 因為每次更新Text屬性,它都有另一個委托要調用。 沒有時間再進行優先級較低的工作了,例如繪制和清空消息隊列。 調用隊列本身開始落后,收集越來越多的等待處理的調用請求。 在極端情況下,這將使您的程序因OutOfMemoryException崩潰,但這會花費很長時間。 即使后台工作人員完成操作,此后,UI線程也忙了很長時間,試圖減少積壓工作。

用戶界面通常無法正常使用,甚至在碰壁之前也無法使用。 用戶只是盯着一個盲目的快速滾動的文本框,該文本框不允許實際讀取任何內容。 本身使用文本框會適得其反,對於用戶編輯列表沒有任何意義。

顯然,您需要以不同的方式執行此操作。 在調用之前,至少要在StringBuilder中收集一堆文件。 這將使TextBox不必經常重新分配。 每隔50毫秒調用一次就沒有任何意義了,這幾乎相當於人眼看到變化而不會變得模糊的速度。 大多數執行此操作的程序僅顯示迭代的文件示例 ,以便用戶對進度有一些反饋。 在這種情況下,將所有數據收集在StringBuilder中並且在文件迭代完成之前不更新TextBox是完全合理的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM