Добрый день.
Есть задача распарсить огромный XML файл (1ТБ) и занести данные в БД.
В одном единственном потоке это всё работает очень медленно, и парсер закончит свою работу приблизительно через три года :D
В общем нужно как-то грамотно разбить парсинг на несколько потоков. Есть варианты?
P.S. с многопоточностью в C# я еще ни разу не работал.
Вот код, который у меня работает в данный момент:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Npgsql;
namespace MapReader
{
class Program
{
static void Main(string[] args)
{
Console.Write("> ");
string path = Console.ReadLine();
IEnumerable<XElement> root = from el in Root(path) select el;
Osm2Pg pgosm = new Osm2Pg();
pgosm.CreateTables();
foreach (XElement item in root)
{
if (item.Name == "way")
{
long wayID = long.Parse(item.Attribute("id").Value);
Console.WriteLine("way: " + item.Attribute("id").Value);
foreach (XElement nd in item.Elements("nd"))
{
long nodeReference = long.Parse(nd.Attribute("ref").Value);
pgosm.InsertWayNds(wayID, nodeReference);
Console.WriteLine("--nd: " + nd.Attribute("ref").Value);
}
foreach (XElement tag in item.Elements("tag"))
{
string key = tag.Attribute("k").Value;
string value = tag.Attribute("v").Value;
pgosm.InsertWayTags(wayID, key, value);
Console.WriteLine("--tag: " + tag.Attribute("k").Value);
}
}
// проходимя по node.
if (item.Name == "node")
{
// конвертируем координаты из географической системы в декартову.
double lon = double.Parse(item.Attribute("lon").Value);
double lat = double.Parse(item.Attribute("lat").Value);
float x = (float)GeoHelper.lonToX(lon);
float z = (float)GeoHelper.latToY(lat);
long nodeId = long.Parse(item.Attribute("id").Value);
pgosm.InsertNodes(nodeId, x, z);
Console.WriteLine("node: " + x + "," + z);
if (item.HasAttributes)
{
foreach (XElement tag in item.Elements("tag"))
{
string key = tag.Attribute("k").Value;
string value = tag.Attribute("v").Value;
pgosm.InsertNodeTags(nodeId, key, value);
Console.WriteLine("--tag: " + tag.Attribute("k").Value);
}
}
}
}
Console.WriteLine("End of program...");
Console.Read();
}
// магия б***ь...
static IEnumerable<XElement> Root(string path)
{
using (XmlReader reader = XmlReader.Create(path))
{
while (reader.Read())
{
if (reader.Name == "way" || reader.Name == "node")
{
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return el;
}
}
}
}
}
}