如何使用并行 foreach 毫无问题地添加字符串

本文关键字:添加 字符串 无问题 何使用 并行 foreach | 更新日期: 2023-09-27 18:33:48

这是我当前的代码:

Parallel.ForEach(Arguments, Argument =>
{
    if (Argument != Command_Name)
    {
        WebRequest web_request = WebRequest.Create("https://www.aol.com/?command=1&domain=" + Argument);
        web_request.Timeout = 5000;
        ((HttpWebRequest)web_request).UserAgent = "Mozilla Firefox 5.0";
        HttpWebResponse web_response = (HttpWebResponse)web_request.GetResponse();
        StreamReader response = new StreamReader(web_response.GetResponseStream(), Encoding.UTF8);
        Message += Argument + " => " + response.ReadToEnd() + Environment.NewLine;
    }
});

此代码无法正常工作,我正在寻找一个可以正常工作的小替代方案。此代码返回消息字符串中的一些参数...添加多线程字符串的好方法是什么?这就是我所需要的。

更多信息:消息字符串有时会返回 a、b 和 c,而其他字符串只会返回 a 或 b...

我感谢这方面的任何帮助,谢谢!

如何使用并行 foreach 毫无问题地添加字符串

您可以使用线程安全集合来存储消息,例如 ConcurrentBag<T> 。然后只需在循环后做出承认:

var messages = new ConcurrentBag<string>();
Parallel.ForEach(Arguments, Argument =>
{
   ... 
   messages.Add(Argument + " => " + response.ReadToEnd());
}
var result = string.Join(Environment.NewLine, messages);
您可以

锁定Message +=部分:

//scoped to the same scope as the Message object
private Object thisLock = new Object();
var textResult = response.ReadToEnd() + Environment.NewLine;
lock(thisLock)
{
    Message += Argument + " => " + textResult;
}

用于收集元素AsParallel()更合适:

var lines = Arguments.AsParallel().Select(Argument =>
{
    if (Argument == Command_Name) return null;
    WebRequest web_request = WebRequest.Create("https://www.aol.com/?command=1&domain=" + Argument);
    web_request.Timeout = 5000;
    ((HttpWebRequest)web_request).UserAgent = "Mozilla Firefox 5.0";
    HttpWebResponse web_response = (HttpWebResponse)web_request.GetResponse();
    StreamReader response = new StreamReader(web_response.GetResponseStream(), Encoding.UTF8);
    return Argument + " => " + response.ReadToEnd();
}).ToArray();
var concate = string.Join(Environment.NewLine, lines);

您可以使用并发集合,然后将其转换为一个字符串

var ThreadSafeList = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(Arguments, Argument =>
{
    if (Argument != Command_Name)
    {
        WebRequest web_request = WebRequest.Create("https://www.aol.com/?command=1&domain=" + Argument);
        web_request.Timeout = 5000;
        ((HttpWebRequest)web_request).UserAgent = "Mozilla Firefox 5.0";
        HttpWebResponse web_response = (HttpWebResponse)web_request.GetResponse();
        StreamReader response = new StreamReader(web_response.GetResponseStream(), Encoding.UTF8);
        ThreadSafeList.Add(Argument + " => " + response.ReadToEnd());                    
    }
});
string Result = string.Join("", ThreadSafeList);

或者尝试锁定要写入的项目。

StringBuilder Message = new StringBuilder();
Parallel.ForEach(Arguments, Argument =>
{
    if (Argument != Command_Name)
    {
        WebRequest web_request = WebRequest.Create("https://www.aol.com/?command=1&domain=" + Argument);
        web_request.Timeout = 5000;
        ((HttpWebRequest)web_request).UserAgent = "Mozilla Firefox 5.0";
        HttpWebResponse web_response = (HttpWebResponse)web_request.GetResponse();
        StreamReader response = new StreamReader(web_response.GetResponseStream(), Encoding.UTF8);
        lock(Message) //locking here
        {
           Message.AppendLine(Argument + " => " + response.ReadToEnd());
        }
    }
});
<</div> div class="answers">

在这种情况下,实现线程安全 wuold 可能最好涉及 lock 语句。请记住,永远不要锁定您没有独占访问权限的对象,在本例中为 cabe 方法范围。

object key = new object(); // Empty object serves lightest for locks
Parallel.ForEach(Arguments, Argument =>
{
    if (Argument != Command_Name)
    {
        WebRequest web_request = WebRequest.Create("https://www.aol.com/?command=1&domain=" + Argument);
        web_request.Timeout = 5000;
        ((HttpWebRequest)web_request).UserAgent = "Mozilla Firefox 5.0";
        HttpWebResponse web_response = (HttpWebResponse)web_request.GetResponse();
        StreamReader response = new StreamReader(web_response.GetResponseStream(), Encoding.UTF8);
        lock(key)
            Message += Argument + " => " + response.ReadToEnd() + Environment.NewLine;
    }
});