2014-02-11 31 views
2

我有一個帳戶列表。我想用網站上的所有帳戶登錄。我想使用Parallel.ForEach來處理所有帳戶。 這是我的代碼如下所示:Parallel.For WebRequests - 第一個請求只是無所作爲

Parallel.ForEach(Accounts, 
    acc => 
    { 
     acc.WebProxy = null; 
     acc.Channel = "pelvicpaladin__"; 
     Debug.WriteLine("Connecting to {0}.", new object[] { acc.Username }); 
     acc.ConnectToIrc().Wait(); 
    }); 

一切正常,只是一個單一的問題罰款: 在帳戶列表中的第一個帳戶不起作用。內部我必須使用多個請求(這不僅僅是登錄)。第一個請求什麼都不做。如果我打破調試器,則沒有可用的源。

我有大約12個帳戶。我試圖從列表中刪除第一個帳戶。但問題仍然是一樣的(現在新的第一(舊的第二個)帳戶失敗)。

而現在很奇怪的一點: 如果我不使用Parallel.For,一切工作正常。

foreach (var acc in Accounts) 
{ 
    acc.WebProxy = null; 
    Debug.WriteLine("Connecting to {0}.", new object[] { acc.Username }); 
    await acc.ConnectToIrc(); 
} 

再次:除了列表中的第一個帳戶以外,一切都正常。它始終是第一個(它不取決於列表包含多少個帳戶或者哪個帳戶是第一個帳戶)。

有沒有人有任何想法?

編輯:這是我如何創建WebRequests:

private async Task<string> GetResponseContent(HttpWebRequest request) 
{ 
    if (request == null) 
     throw new ArgumentNullException("request"); 

    using (var response = await request.GetResponseAsync()) 
    { 
     return await GetResponseContent((HttpWebResponse)response); 
    } 
} 

private async Task<string> GetResponseContent(HttpWebResponse response) 
{ 
    if (response == null) 
     throw new ArgumentNullException("response"); 

    using (var responseStream = response.GetResponseStream()) 
    { 
     return await new StreamReader(responseStream).ReadToEndAsync(); 
    } 
} 

private HttpWebRequest GetRequest(string url) 
{ 
    if (String.IsNullOrWhiteSpace(url)) 
     throw new ArgumentNullException("url"); 

    try 
    { 
     HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 
     request.CookieContainer = _cookieContainer; 
     request.Referer = url; 
     request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; 
     request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 GTB6 (.NET CLR 3.5.30729)"; 
     if (_webProxy != null) 
      request.Proxy = WebProxy.WebProxy; 

     request.KeepAlive = true; 
     request.Timeout = 30000; 

     return request; 
    } 
    catch (Exception ex) 
    { 
     ErrorLogger.Log(String.Format("Could not create Request on {0}.", url), ex); 
     return null; 
    } 
} 
+0

我想這個問題是在'ConnectToIrc'實現。你可以分享該代碼嗎? – wdosanjos

+0

這是相當多的代碼。許多請求,但我可以告訴你我是如何創建請求(順便說一句,我已經檢查是否所有的反應都被處置)。 –

+0

.Wait()是Task.Wait(),對嗎?似乎不需要,將其刪除。最有可能的第一個動作是在調用線程上執行的,也許它會在您等待足夠長時間後執行?第一個可以是最後一個。 –

回答

3

你'重新陷入典型的等待僵局。問題是您撥打ConnectToIrc時正在使用await並捕獲同步上下文。他們正在試圖將主線的延續集中在一起。問題是您的主線程正忙於阻止呼叫Parallel.ForEach。它不允許任何延續運行。主線程正在繼續等待繼續,繼續等待主線程自由運行。僵局。

這是(一個原因)爲什麼你不應該同步等待異步操作。

相反,只需啓動所有異步操作並使用WhenAll等待它們全部完成。有沒有必要創建新線程,或者使用線程池等

var tasks = new List<Task>(); 
foreach (var acc in Accounts) 
{ 
    acc.WebProxy = null; 
    Debug.WriteLine("Connecting to {0}.", new object[] { acc.Username }); 
    tasks.Add(acc.ConnectToIrc()); 
} 
await Task.WhenAll(tasks); 

這不像你的第二個例子,將執行所有並行異步操作,同時還異步等待。

0

再次更新:

var tasks = Accounts.Select(MyTask).ToList(); 
    await Task.WhenAll(tasks); 

,那麼你可以寫一個名爲方法:

private Task MyTask(Account acc) 
    { 
     acc.WebProxy = null; 
     Debug.WriteLine("Connecting to {0}.", new object[] { acc.Username }); 
     return acc.ConnectToIrc(); 
    } 

感謝小費

+0

爲什麼? ____________ –

+0

Parallel.ForEach也經常給我很難 – DrinkBird

+0

嗯,我不知道爲什麼。但是是對的。 It works @HenkHolterman 還想知道爲什麼。 –

相關問題