我必须处理大约170.000个文件,并且想要使用多个线程。 文件名按照Year-Number格式顺序排列,并按文件夹中的年份排序。 (但它们可以都在同一个文件夹中)。 不同年份有不同的文件数。文件很小,每个文件只有几个(10 <大小<20)KB。
处理它们的顺序是无关紧要的,因为处理任务的输出将存储在SQL数据库中。 最好的方法是什么?没有打开两次相同的文件?
答案 0 :(得分:1)
可能的解决方案之一是使用生产者/消费者设计模式。
您的制作人将获得一个文件列表并提供一些ProducerConsumer
队列。您的使用者将处理从队列中获取的文件(或文件路径)并对其进行处理(插入到您的数据库中)。使用这种方法,每个文件只会被处理一次。
C# producer/consumer SO问题中描述了ProducerConsumer
队列的问题。
修改强>
然而,任务可能会变得复杂,例如
答案 1 :(得分:0)
我说每年1个帖子。 每个'Year Thread'读取以该年份编号开头的文件,然后连续读取它们。 至于进入数据库,我建议你
另一个解决方案是,线程为文件生成insert语句,然后执行该文件以执行插入,或者您可以使用批量插入工具。但这取决于表结构和DBMS
答案 2 :(得分:0)
这是一个小例子:
public static class FilesProcessor
{
private static List<FileProcessor> m_FileProcessors;
public static void Start()
{
m_FileProcessors = new List<FileProcessor>();
for (Int32 year = 2005; year < DateTime.Now.Year; ++year)
InstanciateFileProcessor(year);
while (!FinishedLoading())
Application.DoEvents();
}
public static void Stop()
{
foreach (FileProcessor processor in m_FileProcessors)
processor.Stop()
m_FileProcessors.Clear();
m_FileProcessors = null;
}
private static Boolean FinishedLoading()
{
foreach (FileProcessor processor in m_FileProcessors)
{
if (processor.IsAlive() && !processor.FinishedLoading())
return false;
}
return true;
}
private static void InstanciateFileProcessor(Int32 year)
{
FileProcessor processor = new FileProcessor(year);
processor.Start();
m_FileProcessors.Add(processor);
}
}
然后是FileProcessor类:
public sealed class FileProcessor
{
private Int32 m_Year;
public Boolean IsAlive()
{
return ((m_Thread != null) && m_Thread.IsAlive);
}
public Boolean FinishedLoading()
{
return ((m_Thread == null) || m_Thread.Join(10));
}
public FileProcessor(Int32 year)
{
m_Year = year;
m_Thread = new Thread(Load);
m_Thread.Name = "Background File Processor";
}
public void Start()
{
if (m_Thread != null)
m_Thread.Start();
}
public void Stop()
{
if ((m_Thread != null) && m_Thread.IsAlive)
m_Thread.Abort();
}
private void Load()
{
// Browse the Year folder...
// Get and read all fines one by one...
}
}
答案 3 :(得分:0)
我可以在这里看到两种可能的方法。
首先,将您的问题分成两部分。 1 - 确定要处理的内容,2 - 进行处理。第1部分可能必须自行运行,因此您最终会得到100%准确的需要处理的列表。然后,您可以实现关于拆分列表和引入多个线程的奇特(或非常非常奇特)的逻辑。
其次,做一些与@CarlosGrappa建议类似的事情。所以基本上你用自己的“预编程”过滤器创建每个线程。卡洛斯建议,这可能是一年。或者,您可以创建24个线程,每个小时一个文件时间戳。或者60个线程,每个线程查看一小时后的特定分钟。它基本上可以为您提供一个明确的标准,即(a)尽可能均匀地分割负载,以及(b)保证数据文件只处理一次。
显然,这些方法中的第二种方法运行得更快,但您必须更加深入地考虑如何拆分文件。使用第一种方法,一旦获得完整列表,您基本上可以在处理器中同时丢弃100个,1000个或10000个等文件,而不会过于聪明地使用它们。
答案 4 :(得分:0)
使用.Net的并行类有什么问题?
将一个集合传递给并行的foreach循环。 .Net为您完成所有分配。您还可以传入自定义分区程序,以便可以使用块分区。块分区导致线程不断要求更多任务。如果你不使用块分区,那么所有的工作都会被预先分配,导致某些任务比其他任务花费更长的时间(这可能会导致某些线程空闲,而一个线程仍有工作要做)。