-2

これは、2 つのバックグラウンドワーカーを持つバックグラウンドワーカーのクラスです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HtmlAgilityPack;
using System.Net;
using System.Windows.Forms;
using System.ComponentModel;
using System.Threading;

namespace GatherLinks
{
    class BackgroundWebCrawling
    {
        public string f;
        int counter = 0;
        List<string> WebSitesToCrawl;
        int MaxSimultaneousThreads;
        public BackgroundWorker mainBackGroundWorker;
        BackgroundWorker secondryBackGroundWorker;
        WebcrawlerConfiguration webcrawlerCFG;
        List<WebCrawler> webcrawlers;
        int maxlevels;
        public event EventHandler<BackgroundWebCrawlingProgressEventHandler> ProgressEvent;
        ManualResetEvent _busy = new ManualResetEvent(true);


        public BackgroundWebCrawling()
        {
            webcrawlers = new List<WebCrawler>();
            mainBackGroundWorker = new BackgroundWorker();
            mainBackGroundWorker.WorkerSupportsCancellation = true;
            mainBackGroundWorker.DoWork += mainBackGroundWorker_DoWork;
        }

        private void mainBackGroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                BackgroundWorker worker = sender as BackgroundWorker;
                for (int i = 0; i < WebSitesToCrawl.Count; i++)
                {
                    _busy.WaitOne();
                    if ((worker.CancellationPending == true))
                    {
                        e.Cancel = true;
                        break;
                    }
                    while (counter >= MaxSimultaneousThreads)
                    {
                        Thread.Sleep(10);
                    }


                    WebCrawler wc = new WebCrawler(webcrawlerCFG);
                    webcrawlers.Add(wc);
                    counter++;
                    secondryBackGroundWorker = new BackgroundWorker();
                    secondryBackGroundWorker.DoWork += secondryBackGroundWorker_DoWork;
                    object[] args = new object[] { wc, WebSitesToCrawl[i] };
                    secondryBackGroundWorker.RunWorkerAsync(args);



                }
                while (counter > 0)
                {
                    Thread.Sleep(10);
                }
            }
            catch
            {
                MessageBox.Show("err");
            }
        }

        private void secondryBackGroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {


            try
            {
                object[] args = (object[])e.Argument;
                WebCrawler wc = (WebCrawler)args[0];
                string mainUrl = (string)args[1];
                wc.ProgressEvent += new EventHandler<WebCrawler.WebCrawlerProgressEventHandler>(x_ProgressEvent);
                wc.webCrawler(mainUrl, maxlevels);


                counter--;
            }
            catch
            {
                MessageBox.Show("err");
            }
        }

        public void Start(List<string> sitestocrawl, int threadsNumber, int maxlevels, WebcrawlerConfiguration wccfg)
        {
            this.maxlevels = maxlevels;
            webcrawlerCFG = wccfg;
            WebSitesToCrawl = sitestocrawl;
            MaxSimultaneousThreads = threadsNumber;
            mainBackGroundWorker.RunWorkerAsync();
        }

        private void x_ProgressEvent(object sender, WebCrawler.WebCrawlerProgressEventHandler e)
        {

            Object[] temp_arr = new Object[8];
            temp_arr[0] = e.csFiles;
            temp_arr[1] = e.mainUrl;
            temp_arr[2] = e.levels;
            temp_arr[3] = e.currentCrawlingSite;
            temp_arr[4] = e.sitesToCrawl;
            temp_arr[5] = e.done;
            temp_arr[6] = e.failedUrls;
            temp_arr[7] = e.failed;
            OnProgressEvent(temp_arr); 
        }

        private void GetLists(List<string> allWebSites)
        {

        }

        public class BackgroundWebCrawlingProgressEventHandler : EventArgs
        {
            public List<string> csFiles { get; set; }
            public string mainUrl { get; set; }
            public int levels { get; set; }
            public List<string> currentCrawlingSite { get; set; }
            public List<string> sitesToCrawl { get; set; }
            public bool done { get; set; }
            public int failedUrls { get; set; }
            public bool failed { get; set; }
        }

        protected void OnProgressEvent(Object[] some_params) 
        {


            if (ProgressEvent != null)
                ProgressEvent(this,
                    new BackgroundWebCrawlingProgressEventHandler()
                    {
                        csFiles = (List<string>)some_params[0],
                        mainUrl = (string)some_params[1],
                        levels = (int)some_params[2],
                        currentCrawlingSite = (List<string>)some_params[3],
                        sitesToCrawl = (List<string>)some_params[4],
                        done = (bool)some_params[5],
                        failedUrls = (int)some_params[6],
                        failed = (bool)some_params[7]
                    });
        }

        private void PauseWorker()
        {
            if (mainBackGroundWorker.IsBusy)
            {
                _busy.Reset();
            }
        }

        private void ContinueWorker()
        {
            _busy.Set();
        }

        public void CancelWorker()
        {
            ContinueWorker();
            mainBackGroundWorker.CancelAsync();
        }

    }
}

これは、操作を中止するためにクリックするボタン クリック イベントです。

private void button3_Click(object sender, EventArgs e)
        {
            bgwc.CancelWorker();
            cancel = true;
            wcfg.toCancel = cancel;
        }

ボタンをクリックすると、BackgroundWebCrawling クラスに移動して実行します。

public void CancelWorker()
        {
            ContinueWorker();
            mainBackGroundWorker.CancelAsync();
        }

しかし、何らかの理由で、代わりにバックグラウンドワーカーをすぐに停止して、現在のプロセスが約2〜3〜5秒終了するまで待機/ハングアップしてから停止します。代わりに、Form1 への移動とこの部分の実行をすぐに停止します。

private void bgwc_ProgressEvent(object sender, BackgroundWebCrawling.BackgroundWebCrawlingProgressEventHandler e)
        {
            this.Invoke(new MethodInvoker(delegate { label7.Text = e.sitesToCrawl.Count.ToString(); }));
            this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, "Level: " + e.levels.ToString(), Color.Green); }));
            this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, "   Loading The Url:   ", Color.Red); }));
            this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, e.mainUrl + "...", Color.Blue); }));
            if (e.done == true)
            {


                    this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Done " + Environment.NewLine, Color.Red); }));
                    doneWebPages++;
                    this.Invoke(new MethodInvoker(delegate { label12.Text = doneWebPages.ToString(); }));

            }
            if (e.failed == true)
            {
                this.Invoke(new MethodInvoker(delegate { label10.Text = e.failedUrls.ToString(); }));
                this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Failed " + Environment.NewLine, Color.Green); }));
            }
            if (e.failedUrls > 0)
            {
                this.Invoke(new MethodInvoker(delegate { label10.Text = e.failedUrls.ToString(); }));
                e.failed = true;
                if (e.failed == true)
                {
                    this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Failed " + Environment.NewLine, Color.Green); }));
                    e.failed = false;
                }
            }
            this.Invoke(new MethodInvoker(delegate { label13.Text = (e.failedUrls + doneWebPages).ToString(); }));
        }

その後、BackgroundWebCrawling クラスに戻り、次のようにします。

if (ProgressEvent != null)
                ProgressEvent(this,
                    new BackgroundWebCrawlingProgressEventHandler()
                    {
                        csFiles = (List<string>)some_params[0],
                        mainUrl = (string)some_params[1],
                        levels = (int)some_params[2],
                        currentCrawlingSite = (List<string>)some_params[3],
                        sitesToCrawl = (List<string>)some_params[4],
                        done = (bool)some_params[5],
                        failedUrls = (int)some_params[6],
                        failed = (bool)some_params[7]
                    });

次に、同じクラスで次の行を実行します。

OnProgressEvent(temp_arr);/// このクラスのデータ + 追加データを Form1.. に送信します。

そして、このすべての後、Form1 の完了イベントに到達します。

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button3.Enabled = false;
            checkBox1.Enabled = true;
            checkBox2.Enabled = true;
            numericUpDown1.Enabled = true;
            button1.Enabled = true;
            button2.Enabled = true;
            this.Text = "Web Crawling";
            if (cancel == true)
            {
                label6.Text = "Process Cancelled";
            }

問題は、ボタンをクリックしたときに操作を中止せず、最初にプロセスを終了するのを待っているのはなぜですか? たぶん、2番目の背景も何らかの形で停止/中止する必要がありますか?

4

1 に答える 1

0

まず、これはやり過ぎのコードのように思えますが、必要なのかもしれません...

第二に、キャンセルは実際には何もキャンセルしていません。アクションを実行する必要があるフラグを設定するだけです。そのフラグに応答するとbreak、カウントが 0 に戻るのを待つだけです。すぐに停止してから、しないbreakでください。return

休憩後も、ワーカーで次のことを行っています。counterキャンセル時に を 0 に設定することもできます。しかし、リターンはより将来の証拠です。

while (counter > 0)
{
    Thread.Sleep(10);
}
于 2013-10-15T17:20:00.563 に答える