c# - Parallel.For WebRequests - 第一个请求什么也不做

标签 c# async-await httpwebrequest parallel.foreach

我有一个帐户列表。我想使用网站上的所有帐户登录。我想使用 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/

相关文章:

c# - 如何将可选文件复制到 VS 2017 中的输出目录?

c# - Task.WaitAll 一直在循环

c# - 如果更改 Thread.CurrentThread.CurrentCulture,则 HttpWebRequest 超时

java - 在 Eclipse 中查看 http POST 和 GET 数据的最简单/最佳方法?任何插件/工具?

c# - 单击 HTML 链接时在 ASP.NET 中调用 C# 函数

c# - 如何在 linq 中执行 WHERE IN

c# - 调试在关键字 'where' 附近产生错误的语法

javascript - Promise.all 返回函数

javascript - 递归 Promise.all?

c# - 使用 HttpWebRequest 时如何限制带宽使用?