【问题标题】:Why can I not recursively call a Worker_DoWork function?为什么我不能递归调用 Worker_DoWork 函数?
【发布时间】:2020-05-10 23:02:41
【问题描述】:

我在 c# 中有一个使用 Sytem.Net.Sockets 的 tcp 服务器和客户端。我的工人功能如下

   private void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        byte[] buffer = new byte[1];
        socket.Receive(buffer);
        chatTextBox.Text = buffer[0].ToString();        
    }

我在服务器创建后调用它,一旦它收到来自客户端的消息,它就会将它写在屏幕上并停止。我的问题是我希望它最后再次调用自己,以便等待另一条消息显示。如果我只是添加 worker.RunWorkerAsync();在底部它不起作用,但是如果我只是从另一个按钮调用它,它会起作用并接收和写入消息。

【问题讨论】:

    标签: c# sockets networking tcp


    【解决方案1】:

    BackgroundWorker “包裹”在一个线程周围并帮助您完成所有工作。这是一种非常过时的多任务处理方法,你不应该再在生产代码中使用它。然而,它也是我所知道的多任务处理的最佳“训练轮”。

    您的基本方法有缺陷。 BGW 不允许这样做实际上只是在帮助您学习需要学习的东西。代码中的错误列表:

    • 您正在直接在 DoWork 中访问 GUI 元素。不要那样做。只在 ReportProgress 和 RunWorker 完成事件中编写 UI。这是general Multithreading rule,得益于 BGW 的设计。
    • 您正在尝试在线程完成之前重新启动线程。如果您想重新启动它,RunWorkerCompleted 将是正确的地方
    • 然而,更明智的做法是让 BackgroundWorker 的核心成为一个半无限循环。一直运行到取消的东西。通常将信息与报告一起分发不是一个好主意,但在这种情况下,这是我的最佳主意。

    我唯一能给你的就是我的旧 BGW 示例代码:

    #region Primenumbers
    private void btnPrimStart_Click(object sender, EventArgs e)
    {
        if (!bgwPrim.IsBusy)
        {
            //Prepare ProgressBar and Textbox
            int temp = (int)nudPrim.Value;
            pgbPrim.Maximum = temp;
            tbPrim.Text = "";
    
            //Start processing
            bgwPrim.RunWorkerAsync(temp);
        }
    }
    
    private void btnPrimCancel_Click(object sender, EventArgs e)
    {
        if (bgwPrim.IsBusy)
        {
            bgwPrim.CancelAsync();
        }
    }
    
    private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
    {
        int highestToCheck = (int)e.Argument;
        //Get a reference to the BackgroundWorker running this code
        //for Progress Updates and Cancelation checking
        BackgroundWorker thisWorker = (BackgroundWorker)sender;
    
        //Create the list that stores the results and is returned by DoWork
        List<int> Primes = new List<int>();
    
    
        //Check all uneven numbers between 1 and whatever the user choose as upper limit
        for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
        {
            //Report progress
            thisWorker.ReportProgress(PrimeCandidate);
            bool isNoPrime = false;
    
            //Check if the Cancelation was requested during the last loop
            if (thisWorker.CancellationPending)
            {
                //Tell the Backgroundworker you are canceling and exit the for-loop
                e.Cancel = true;
                break;
            }
    
            //Determin if this is a Prime Number
            for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
            {
                if (PrimeCandidate % j == 0)
                    isNoPrime = true;
            }
    
            if (!isNoPrime)
                Primes.Add(PrimeCandidate);
        }
    
        //Tell the progress bar you are finished
        thisWorker.ReportProgress(highestToCheck);
    
        //Save Return Value
        e.Result = Primes.ToArray();
    }
    
    private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        pgbPrim.Value = e.ProgressPercentage;
    }
    
    private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        pgbPrim.Value = pgbPrim.Maximum;
        this.Refresh();
    
        if (!e.Cancelled && e.Error == null)
        {
            //Show the Result
            int[] Primes = (int[])e.Result;
    
            StringBuilder sbOutput = new StringBuilder();
    
            foreach (int Prim in Primes)
            {
                sbOutput.Append(Prim.ToString() + Environment.NewLine);
            }
    
            tbPrim.Text = sbOutput.ToString();
        }
        else 
        {
            tbPrim.Text = "Operation canceled by user or Exception";
        }
    }
    #endregion
    

    【讨论】:

    • 第二个添加 RunWorkerComplete 的建议正是我想要的!我知道这是非常糟糕的编码,但我只是想了解这个过程到底是如何工作的,这很有帮助。你说后台工作者是一个过时的东西,我应该用什么来代替它来运行我的多任务处理?任何链接总是很感激!只是制作一个简单的客户端/服务器 tcp 聊天应用程序!
    • @Rainflow901 对于初学者来说,BGW 是最理想的。它基本上通过它的限制和规则迫使你进入正确的模式。当前的“事物”是异步机制。一种无需一直使用线程即可进行多任务处理的方法。通常线程应该只在两种情况下使用:a)工作是 CPU 绑定的。但这些情况很少见。 b) 大型服务器。这些一直到 ThreadPools。线程带来的隔离可以提供很大帮助。
    猜你喜欢
    • 1970-01-01
    • 2019-09-13
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    • 2014-01-18
    • 1970-01-01
    • 2014-05-04
    • 1970-01-01
    相关资源
    最近更新 更多