后台多线程(无响应 UI)

Background multithreading (unresponsive UI)

基本上我一直在使用多线程,但它并没有按应有的方式工作。我立即尝试在标题中描述问题以在网上找到答案,但没有找到任何相关内容。

这是我开发的一个应用程序,用于更好地理解多任务处理,以便我可以在实际应用程序中有效地使用它。

所以基本上它所做的是在文本框中写一些东西并选择你想要的线程数,它会在底部附加日志框。所以它会显示每个线程有多少次运行 但是问题是它仍然使UI在后台冻结。

这是它在 3 个线程上的输出(它可以处理少量(少于 10 个)线程):

这里是完整的代码-

public partial class thread : Form
{
    Thread[] threads;
    int amountOf;
    bool stop = false;
    int threadAmt = 0;

    public thread()
    {
        InitializeComponent();
    }

    delegate void SetTextCallback(string text);

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        amountOf = (int)amtThreads.Value;
        threads = new Thread[amountOf];
        //Define threads
        for (int i = 0; i < amountOf; i++)
        {
            threads[i] = new Thread(new ThreadStart(job));
        }
       //Start threads
       foreach (Thread t in threads)
       {
           t.IsBackground = true;
           t.Start();
       }
    }

    private void logIt(string text)
    {
        if (outputResult.InvokeRequired)
        {
            SetTextCallback cb = new SetTextCallback(logIt);
            Invoke(cb, new object[] { text });
        }
        else
            outputResult.AppendText(text);
    }

    private void job()
    {
        int threadNum = threadAmt++;
        int howMany = 0;
        do
        {
            howMany++;
            logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
            Thread.Sleep(1);
        }
        while (!stop);
    }

    private void Start_Click(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
        Start.Enabled = false;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
            MessageBox.Show("Error: " + e.Error.Message);
        else if (e.Cancelled)
            MessageBox.Show("Application canceled.");
    }

    private void Stop_Click(object sender, EventArgs e)
    {
        stop = true;
        backgroundWorker1.CancelAsync();
        Stop.Enabled = false;
    }

    private void Clear_Click(object sender, EventArgs e)
    {
        outputResult.Clear();
    }
}

UI放置10个或更多线程后继续冻结。 我想知道的另一件事是暂停和恢复线程。当你停止线程循环然后 re-enable 它只会显示一个结果。它不会继续循环。

你的问题不是创建过多的线程而是你的线程过度更新UI

你的 job 方法有一个非常紧密的循环,你调用 logIt 然后休眠 一毫秒然后重复这个过程。 日志整理调用到调用 outputResult.AppendText(text); 的 UI 线程。这种编组发生在消息泵上。

您实际上是在对 TextBox 进行更新,使消息泵溢出,因此 UI 变得无响应,无法处理其他任何内容。

将其乘以 10 个线程,所有日志记录之间的等待时间极短,您的 UI 将冻结。

考虑增加 Thread.Sleep 以说 Thread.Sleep(500) 1/2 秒。

更改此代码:

private void job()
{
    int threadNum = threadAmt++;
    int howMany = 0;
    do
    {
        howMany++;
        logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
        Thread.Sleep(1); // Oww!!  Should this have been 1000 instead of 1.   1000 is 1 second.
    }
    while (!stop);
}

...至:

private void job()
{
    int threadNum = threadAmt++;
    int howMany = 0;
    do
    {
        howMany++;
        logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
        Thread.Sleep(500); // e.g. 1/2 second 
    }
    while (!stop);
}

替代设计

很高兴您对线程感兴趣。自从引入 Thread 以来,.NET 使线程处理变得更加容易,特别是当线程需要操作 UI 时。现在通常最好不要显式创建线程,而是使用替代 API。

您可能想通过 asyncawait 关键字查看 .NET 异步方法,因为它们对您的情况可能非常有用。

另一个话题