C# 在解析时同时启动所有线程
C# Starting all thread in the same time while parsing
我目前正在学习 C#,过去两天我一直在研究 XML 解析器。它实际上工作正常我的问题是解析超过 10k 页所花费的时间。这是我的代码。
public static void startParse(int id_min, int id_max, int numberofthreads)
{
int start;
int end;
int part;
int threadnbrs;
threadnbrs = numberofthreads;
List<Thread> workerThreads;
List<string> results;
part = (id_max - id_min) / threadnbrs;
start = id_min;
end = 0;
workerThreads = new List<Thread>();
results = new List<string>();
for (int i = 0; i < threadnbrs; i++)
{
if (i != 0)
start = end + 1;
end = start + (part);
if (i == (threadnbrs - 1))
end = id_max;
int _i = i;
int _start = start;
int _end = end;
Thread t = new Thread(() =>
{
Console.WriteLine("i = " + _i);
Console.WriteLine("start =" + _start);
Console.WriteLine("end =" + _end + "\r\n");
string parse = new ParseWH().parse(_start, _end);
lock (results)
{
results.Add(parse);
}
});
workerThreads.Add(t);
t.Start();
}
foreach (Thread thread in workerThreads)
thread.Join();
File.WriteAllText(".\result.txt", String.Join("", results));
Console.Beep();
}
我实际上在做的是在不同线程中拆分需要解析的一系列元素,以便每个线程处理 X 个元素。
每 100 个元素大约需要 20 秒。
然而我花了 17 分钟来解析 10 0000 个元素。
我需要的是每个线程同时处理这 10 000 个元素中的 100 个,这样它可以在 20 秒内完成。有解决办法吗?
解析代码:
public string parse(int id_min, int id_max)
{
XmlDocument xml;
WebClient user;
XmlElement element;
XmlNodeList nodes;
string result;
string address;
int i;
//Console.WriteLine(id_min);
//Console.WriteLine(id_max);
i = id_min;
result = "";
xml = new XmlDocument();
while (i <= id_max)
{
user = new WebClient();
// user.Headers.Add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");
user.Encoding = UTF8Encoding.UTF8;
address = "http://fr.wowhead.com/item=" + i + "?xml";
if (address != null)
xml.LoadXml(user.DownloadString(new Uri(address)));
element = xml.DocumentElement;
nodes = element.SelectNodes("/wowhead");
if (xml.SelectSingleNode("/wowhead/error") != null)
{
Console.WriteLine("error " + i);
i++;
continue;
}
result += "INSERT INTO item_wh (entry, class, subclass, displayId, ,quality, name, level) VALUES (";
foreach (XmlNode node in nodes)
{
// entry
result += node["item"].Attributes["id"].InnerText;
result += ", ";
// class
result += node["item"]["class"].Attributes["id"].InnerText;
result += ", ";
// subclass
result += node["item"]["subclass"].Attributes["id"].InnerText;
result += ", ";
// displayId
result += node["item"]["icon"].Attributes["displayId"].InnerText;
result += ", ";
// quality
result += node["item"]["quality"].Attributes["id"].InnerText;
result += ", \"";
// name
result += node["item"]["name"].InnerText;
result += "\", ";
// level
result += node["item"]["level"].InnerText;
result += ");";
// bakcline
result += "\r\n";
}
i++;
}
return (result);
}
CPU 绑定工作(例如解析)的最佳解决方案是启动与机器中核心数量一样多的线程,少于此数量并且您没有利用所有核心,不止于此,而且过度 context-switching 可能会影响性能。
所以基本上,threadnbrs 应该设置为 Environment.ProcessorCount
此外,考虑使用并行 class 而不是自己创建线程:
Parallel.ForEach(thingsToParse, (somethingToParse) =>
{
var parsed = Parse(somethingToParse);
results.Add(parsed);
});
您必须同意它看起来更干净,更易于维护。
此外,您最好使用 ConcurrentBag 而不是常规的 List + lock,因为 ConcurrentBag 更适合并发加载,并且可以为您提供更好的性能。
终于!通过同时启动我的应用程序的多个进程让它工作。
表示如果我在 1000 个元素的 10 个过程中有 10 k 个元素 运行。增加流程数量以减少元素数量,并且速度越来越快!
(我目前 运行 正在以非常快的互联网速度上网)并拥有三星 M.2 960 作为存储以及核心 I7 Skylake 6 核
好吧,我找到了“”,它叫做"Thread Pool"我最终决定直接下载XML文件然后直接离线解析文档,而不是直接解析网站到获得 SQL 格式。新方法奏效了,我可以在 9 秒内下载和写入多达 10 000 K XML。我试图将它推到 150 K(所有网站页面),但现在我遇到了一个奇怪的错误,我得到了重复的项目...我将尝试使用正确的池方法重写完整代码,multi Task/Thread, dictionary 和 IEnumerable Containers 交叉手指处理 150 k Item 而不会丢失处理中的数据并且 post 返回完整代码。
我目前正在学习 C#,过去两天我一直在研究 XML 解析器。它实际上工作正常我的问题是解析超过 10k 页所花费的时间。这是我的代码。
public static void startParse(int id_min, int id_max, int numberofthreads)
{
int start;
int end;
int part;
int threadnbrs;
threadnbrs = numberofthreads;
List<Thread> workerThreads;
List<string> results;
part = (id_max - id_min) / threadnbrs;
start = id_min;
end = 0;
workerThreads = new List<Thread>();
results = new List<string>();
for (int i = 0; i < threadnbrs; i++)
{
if (i != 0)
start = end + 1;
end = start + (part);
if (i == (threadnbrs - 1))
end = id_max;
int _i = i;
int _start = start;
int _end = end;
Thread t = new Thread(() =>
{
Console.WriteLine("i = " + _i);
Console.WriteLine("start =" + _start);
Console.WriteLine("end =" + _end + "\r\n");
string parse = new ParseWH().parse(_start, _end);
lock (results)
{
results.Add(parse);
}
});
workerThreads.Add(t);
t.Start();
}
foreach (Thread thread in workerThreads)
thread.Join();
File.WriteAllText(".\result.txt", String.Join("", results));
Console.Beep();
}
我实际上在做的是在不同线程中拆分需要解析的一系列元素,以便每个线程处理 X 个元素。
每 100 个元素大约需要 20 秒。 然而我花了 17 分钟来解析 10 0000 个元素。
我需要的是每个线程同时处理这 10 000 个元素中的 100 个,这样它可以在 20 秒内完成。有解决办法吗?
解析代码:
public string parse(int id_min, int id_max)
{
XmlDocument xml;
WebClient user;
XmlElement element;
XmlNodeList nodes;
string result;
string address;
int i;
//Console.WriteLine(id_min);
//Console.WriteLine(id_max);
i = id_min;
result = "";
xml = new XmlDocument();
while (i <= id_max)
{
user = new WebClient();
// user.Headers.Add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");
user.Encoding = UTF8Encoding.UTF8;
address = "http://fr.wowhead.com/item=" + i + "?xml";
if (address != null)
xml.LoadXml(user.DownloadString(new Uri(address)));
element = xml.DocumentElement;
nodes = element.SelectNodes("/wowhead");
if (xml.SelectSingleNode("/wowhead/error") != null)
{
Console.WriteLine("error " + i);
i++;
continue;
}
result += "INSERT INTO item_wh (entry, class, subclass, displayId, ,quality, name, level) VALUES (";
foreach (XmlNode node in nodes)
{
// entry
result += node["item"].Attributes["id"].InnerText;
result += ", ";
// class
result += node["item"]["class"].Attributes["id"].InnerText;
result += ", ";
// subclass
result += node["item"]["subclass"].Attributes["id"].InnerText;
result += ", ";
// displayId
result += node["item"]["icon"].Attributes["displayId"].InnerText;
result += ", ";
// quality
result += node["item"]["quality"].Attributes["id"].InnerText;
result += ", \"";
// name
result += node["item"]["name"].InnerText;
result += "\", ";
// level
result += node["item"]["level"].InnerText;
result += ");";
// bakcline
result += "\r\n";
}
i++;
}
return (result);
}
CPU 绑定工作(例如解析)的最佳解决方案是启动与机器中核心数量一样多的线程,少于此数量并且您没有利用所有核心,不止于此,而且过度 context-switching 可能会影响性能。
所以基本上,threadnbrs 应该设置为 Environment.ProcessorCount
此外,考虑使用并行 class 而不是自己创建线程:
Parallel.ForEach(thingsToParse, (somethingToParse) =>
{
var parsed = Parse(somethingToParse);
results.Add(parsed);
});
您必须同意它看起来更干净,更易于维护。 此外,您最好使用 ConcurrentBag 而不是常规的 List + lock,因为 ConcurrentBag 更适合并发加载,并且可以为您提供更好的性能。
终于!通过同时启动我的应用程序的多个进程让它工作。
表示如果我在 1000 个元素的 10 个过程中有 10 k 个元素 运行。增加流程数量以减少元素数量,并且速度越来越快! (我目前 运行 正在以非常快的互联网速度上网)并拥有三星 M.2 960 作为存储以及核心 I7 Skylake 6 核
好吧,我找到了“”,它叫做"Thread Pool"我最终决定直接下载XML文件然后直接离线解析文档,而不是直接解析网站到获得 SQL 格式。新方法奏效了,我可以在 9 秒内下载和写入多达 10 000 K XML。我试图将它推到 150 K(所有网站页面),但现在我遇到了一个奇怪的错误,我得到了重复的项目...我将尝试使用正确的池方法重写完整代码,multi Task/Thread, dictionary 和 IEnumerable Containers 交叉手指处理 150 k Item 而不会丢失处理中的数据并且 post 返回完整代码。