我想做一个解析系统中多个文件的独立任务,并按如下方式获取每个文件的版本:
public void obtainVersionList()
{
for(int iterator = 1; iterator < list.length; iterator++) //list stores all the file names
{
Thread t = new Thread( () => GetVersion(ref list[iterator])
//list will again store the fileVersions using GetVersion()
}
}
在这里,
答案 0 :(得分:2)
对于并行执行,我建议您Parallel.ForEach
(或Task
类):
Parallel.ForEach(list, item => GetVersion(ref item));
您使用的TPL然后通常使用线程池为您执行线程管理。但是,您可以使用不同的调度程序实现。一般来说,重复使用线程比产生线程更便宜。
受到韦斯顿建议的启发,我尝试了一种替代方案,可以将其视为创意LINQ用法:
static void Main(string[] args)
{
var seq = Enumerable.Range(0, 10).ToList();
var tasks = seq
.Select(i => Task.Factory.StartNew(() => Foo(i)))
.ToList(); // important, spawns the tasks
var result = tasks.Select(t => t.Result);
// no results are blockingly received before this
// foreach loop
foreach(var r in result)
{
Console.WriteLine(r);
}
}
static int Foo(int i)
{
return i;
}
对于seq
中的每个输入,我创建了Task<T>
做某事。这些任务的Result
收集在result
中,而foreach
之前没有迭代。此代码也会保持结果的顺序。
示例不会修改seq
。这与您希望改变list
的概念不同。
答案 1 :(得分:2)
iterator
变量是通过引用捕获的,而不是通过值捕获的。这使得所有线程共享相同的变量。首先将它复制到循环局部变量,然后在lambda中使用它。
每个人至少都会这样做一次。 C#设计师对这个决定感到遗憾,他们考虑改变它。
答案 2 :(得分:1)
要解决索引越界问题,您可以制作迭代变量的本地副本:
for(int iterator = 1; iterator < list.length; iterator++) //list stores all the file names
{
int iterator1 = iterator;
Thread t = new Thread( () => GetVersion(ref list[iterator1]);
//list will again store the fileVersions using GetVersion()
}
2)如何在解析磁盘中的多个文件时最小化操作时间?
当你有一个机械磁盘时,这不是一个好主意。当每个线程都有机会运行时,你只是在弹跳机械头。坚持使用单个线程进行磁盘I / O.
答案 3 :(得分:0)
不要关闭迭代器变量。相反,创建一个局部变量并关闭它:
public void obtainVersionList()
{
//list stores all the file names
for(int iterator = 1; iterator < list.length; iterator++)
{
//list will again store the fileVersions using GetVersion()
var local = list[iterator];
Thread t = new Thread( () => GetVersion(ref local);
}
}
答案 4 :(得分:0)
您不应让多个线程调整相同的列表。除非列表是线程安全的,否则这不是线程安全的。我不知道类型,但List<string>
不是。
另一件事是你不应该为此创建自己的线程。如果列表是200个文件怎么办,你的PC将停止创建200个线程。让threadpool为您管理合理数量的线程。
此解决方案假设您有.net4。
将GetVersion的签名更改为:private static string GetVersion(string file)
var tasks = new List<Task>();
//start tasks
foreach (var file in list)
{
var localFile = file; //local variable on advice of resharper
tasks.Add(Task<string>.Factory.StartNew(() => GetVersion(localFile)));
}
//wait for them to complete
Task.WaitAll(tasks.ToArray());
//read the results
IEnumerable<string> result = tasks.OfType<Task<string>>().Select(e => e.Result);
//print em out for test
foreach (var str in result)
{
Console.WriteLine(str);
}