簡體   English   中英

ConcurrentBag 跳過一些項目 C#

[英]ConcurrentBag Skiping some items C#

我正在使用 concurrentbag 來抓取 URL,現在它可以很好地處理 500 / 100 個 url,但是當我嘗試抓取 8000 個 url 時。 所有未處理的 URL 和 inputQueue 中的一些待處理項目。

但我正在使用 while (!inputQueue.IsEmpty) 。 因此,它應該循環運行,直到輸入隊列中存在任何項目。

我只想最多運行 100 個線程。 所以,我首先創建 100 個線程並調用“Run()”方法,在該方法中我運行一個循環來獲取項目,直到項目退出輸入隊列並在抓取 url 后添加到輸出隊列。

public ConcurrentBag<Data> inputQueue = new ConcurrentBag<Data>();
    public ConcurrentBag<Data> outPutQueue = new ConcurrentBag<Data>();

    public List<Data> Scrapes(List<Data> scrapeRequests)
    {
        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
        string proxy_session_id = new Random().Next().ToString();

        numberOfRequestSent = 0;

        watch.Start();

        foreach (var sRequest in scrapeRequests)
        {
            inputQueue.Add(sRequest);
        }
        //inputQueue.CompleteAdding();

        var taskList = new List<Task>();
        for (var i = 0; i < n_parallel_exit_nodes; i++) //create 100 threads only
        {
            taskList.Add(Task.Factory.StartNew(async () =>
            {
               await Run();
            }, TaskCreationOptions.RunContinuationsAsynchronously));
        }

        Task.WaitAll(taskList.ToArray());   //Waiting

        //print result
        Console.WriteLine("Number Of URLs Found - {0}", scrapeRequests.Count);
        Console.WriteLine("Number Of Request Sent - {0}", numberOfRequestSent);

        Console.WriteLine("Input Queue - {0}", inputQueue.Count);

        Console.WriteLine("OutPut Queue - {0}", outPutQueue.ToList().Count);
        Console.WriteLine("Success - {0}", outPutQueue.ToList().Where(x=>x.IsProxySuccess==true).Count().ToString());
        Console.WriteLine("Failed - {0}", outPutQueue.ToList().Where(x => x.IsProxySuccess == false).Count().ToString());
        Console.WriteLine("Process Time In - {0}", watch.Elapsed);

        return outPutQueue.ToList();
    }


    async Task<string> Run()
    {
        while (!inputQueue.IsEmpty)
        {
            var client = new Client(super_proxy_ip, "US");

            if (!client.have_good_super_proxy())
                client.switch_session_id();
            if (client.n_req_for_exit_node == switch_ip_every_n_req)
                client.switch_session_id();

            var scrapeRequest = new ProductResearch_ProData();
            inputQueue.TryTake(out scrapeRequest);

            try
            {
                numberOfRequestSent++;

                // Console.WriteLine("Sending request for - {0}", scrapeRequest.URL);
                scrapeRequest.HTML = client.DownloadString((string)scrapeRequest.URL);
                //Console.WriteLine("Response done for - {0}", scrapeRequest.URL);

                scrapeRequest.IsProxySuccess = true;

                outPutQueue.Add(scrapeRequest); //add object to output queue

                //lumanti code
                client.handle_response();
            }
            catch (WebException e)
            {
                Console.WriteLine("Failed");

                scrapeRequest.IsProxySuccess = false;
                Console.WriteLine(e.Message);
                outPutQueue.Add(scrapeRequest); //add object to output queue

                //lumanti code
                client.handle_response(e);
            }

            client.clean_connection_pool();
            client.Dispose();
        }

        return await Task.Run(() => "Done");
    }

這里有多個問題,但它們似乎都不是inputQueue.Count具有非零值的原因。 無論如何,我想指出我能看到的問題。

var taskList = new List<Task>();
for (var i = 0; i < n_parallel_exit_nodes; i++) // create 100 threads only
{
    taskList.Add(Task.Factory.StartNew(async () =>
    {
        await Run();
    }, TaskCreationOptions.RunContinuationsAsynchronously));
}

方法Task.Factory.StartNew不理解異步委托,因此當使用異步 lambda 作為參數調用它時,它返回一個嵌套任務。 在這種情況下,它返回一個Task<Task<string>> 您將此嵌套任務存儲在List<Task>集合中,這是可能的,因為類型Task<TResult>繼承自類型Task ,但這樣做您將失去等待內部任務完成(並獲得結果)的能力. 您只持有對外部任務的引用。 奇跡般地,在這種情況下這不是問題(通常是),因為外部任務完成了所有工作,而內部任務基本上什么都不做(除了使用線程池線程返回一個並非真正意義上的"Done"字符串)任何地方都需要)。

您也不TaskCreationOptions.RunContinuationsAsynchronously任何延續附加到外部任務,因此標志TaskCreationOptions.RunContinuationsAsynchronously似乎是多余的。

// create 100 threads only

您不創建 100 個線程,而是創建 100 個任務。 這些任務被安排在ThreadPool ,由於任務長時間運行,它將立即被餓死,並將每 500 毫秒開始注入一個新線程,直到所有計划任務都分配給一個線程。

var scrapeRequest = new ProductResearch_ProData();
inputQueue.TryTake(out scrapeRequest);

在這里,您實例化了一個ProductResearch_ProData類型的對象,該對象會立即被丟棄並在下一行中成為垃圾收集對象。 TryTake方法將返回從包中移除的對象,如果包為空,則返回null 你忽略了TryTake方法的返回值,這完全有可能是false因為與此同時包可能已經被另一個工作人員清空,然后繼續執行一個可能為空值的scrapeRequest ,導致這種情況出現NullReferenceException

值得注意的是,您從ConcurrentBag<Data>提取了ProductResearch_ProData類型的對象,因此類DataProductResearch_ProDataProductResearch_ProData ,或者代碼中存在轉錄錯誤。

暫無
暫無

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

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