[英]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
類型的對象,因此類Data
繼ProductResearch_ProData
類ProductResearch_ProData
,或者代碼中存在轉錄錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.