Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 后台多线程(无响应UI)_C#_Multithreading_User Interface_Backgroundworker_Freeze - Fatal编程技术网

C# 后台多线程(无响应UI)

C# 后台多线程(无响应UI),c#,multithreading,user-interface,backgroundworker,freeze,C#,Multithreading,User Interface,Backgroundworker,Freeze,从本质上说,我一直在使用多线程,但它并没有按应有的方式工作。我立即试图用一个标题来描述这个问题,以便在网上找到答案,但没有找到任何相关的答案 这是我开发的一个应用程序,它可以更好地理解多任务处理,以便在实际应用中有效地使用 基本上,它是在文本框中写一些东西,然后选择需要多少线程,它会在底部附加日志框。因此,它将显示每个线程已经运行了多少次,但问题是它仍然会使UI在后台冻结 以下是它在3个线程上提供的输出(它可以处理少量(少于10个)线程): 这是完整的代码- public partial c

从本质上说,我一直在使用多线程,但它并没有按应有的方式工作。我立即试图用一个标题来描述这个问题,以便在网上找到答案,但没有找到任何相关的答案

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

基本上,它是在文本框中写一些东西,然后选择需要多少线程,它会在底部附加日志框。因此,它将显示每个线程已经运行了多少次,但问题是它仍然会使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();
    }
}
公共部分类线程:表单
{
线程[]线程;
国际货币基金组织;
bool-stop=false;
int-threadAmt=0;
公共线程()
{
初始化组件();
}
委托无效SetTextCallback(字符串文本);
私有void backgroundWorker1\u DoWork(对象发送方,DoWorkEventArgs e)
{
amountOf=(int)amtThreads.Value;
线程=新线程[amountOf];
//定义线程
对于(int i=0;i
在放置10个或更多线程后,UI继续冻结。
我想知道的另一件事是暂停和恢复线程。当您停止线程循环,然后重新启用它时,它将只显示一个结果。它不会继续循环。

您的问题不在于创建过多的线程,而在于您的线程正在过度更新UI

你的
job
方法有一个非常紧密的循环,你调用
logIt
,然后睡眠一毫秒,然后重复这个过程。日志将调用封送到UI线程,其中
outputResult.AppendText(文本)被调用。此编组通过消息泵进行

基本上,您的消息泵溢出了
文本框的更新,因此用户界面变得没有响应,无法处理任何其他内容

将其乘以10个线程,所有日志记录在日志记录和UI之间的等待时间都很小,将冻结

考虑将
线程.Sleep
增加1/2秒,即
线程.Sleep(500)

更改此代码:

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

您可能希望通过
async
await
关键字查看.NET异步方法,因为它们在您的情况下可能非常有用


另一次的主题

如果目标只是保持UI的响应性,那么当您已经在后台线程中时,我看不到产生其他线程的理由。@UweKeim就像应用程序中指出的那样,这是一个在我将多线程实现到实际应用程序之前进一步改进多线程的测试。如果这个基本的东西不能以我实现它的方式处理多线程,那么这个应用程序将如何工作?这是我第一次在这种情况下使用多线程技术,这是我第一次使用多线程技术,但我也在寻找更有效的代码改进和答案。我怀疑当您大幅增加同时运行的线程数时(为什么您运行的线程数会超过可用的内核数我无法理解…)您只需使用invokererequired检查(后台线程总是需要这些检查)和后续Invoke命令来粉碎UI线程。尝试增加
Thread.Sleep
值。我总是喜欢创建自己的线程。@Lathejockey81我很确定一台普通的计算机能够处理比系统内核更多的线程,而不会使UI没有响应。它可能只是过多的线程;您是否看到我的代码中存在任何可能影响UI冻结的问题?第一次真正使用多线程,实际上没有引用。我通常使用Thread.Sleep(1)来释放内存消耗,因为它在UI中基本上是无法检测到的。你会多分发一点还是增加一个?是的,我肯定能看出成为一个