我有一个帐户列表。我想使用网站上的所有帐户登录。我想使用 Parallel.ForEach 来处理所有帐户。 这就是我的代码的样子:
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();
}
再次:除了列表中的第一个帐户之外,一切正常。它始终是第一个(它不取决于列表包含多少帐户或哪个帐户是第一个帐户)。
有人知道吗?
编辑:这就是我创建 WebRequest 的方式:
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;
}
}
最佳答案
您遇到了典型的等待死锁情况。问题在于您对 ConnectToIrc 的调用正在使用 wait 并捕获同步上下文。他们正在尝试将延续编码到主线程。问题是您的主线程正忙于阻塞对 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);
与第二个示例不同,这将并行执行所有异步操作,同时仍异步等待。
关于c# - Parallel.For WebRequests - 第一个请求什么也不做,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21703919/