【发布时间】:2017-11-03 14:09:14
【问题描述】:
我有大约 100 个文本文件,每个 200MB,我需要解析它们。下面的程序加载文件并并行处理它们。它可以为每个文件创建一个线程,也可以为每个文件创建一个进程。
问题:如果我使用线程,它永远不会使用 100% 的 CPU,并且需要更长的时间才能完成。
THREAD PER FILE
total time: 430 sec
CPU usage 15-20%
CPU frequency 1.2 GHz
PROCESS PER FILE
total time 100 sec
CPU usage 100%
CPU frequency 3.75 GHz
我正在使用 E5-1650 v3 Hexa-Core 和 HT,因此我一次处理 12 个文件。
如何实现线程 100% 的 CPU 利用率?
下面的代码不使用处理结果,因为它不影响问题。
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
namespace libsvm2tsv
{
class Program
{
static void Main(string[] args)
{
var sw = Stopwatch.StartNew();
switch (args[0])
{
case "-t": LoadAll(args[1], LoadFile); break;
case "-p": LoadAll(args[1], RunChild); break;
case "-f": LoadFile(args[1]); return;
}
Console.WriteLine("ELAPSED: {0} sec.", sw.ElapsedMilliseconds / 1000);
Console.ReadLine();
}
static void LoadAll(string folder, Action<string> algorithm)
{
var sem = new SemaphoreSlim(12);
Directory.EnumerateFiles(folder).ToList().ForEach(f=> {
sem.Wait();
new Thread(() => { try { algorithm(f); } finally { sem.Release(); } }).Start();
});
}
static void RunChild(string file)
{
Process.Start(new ProcessStartInfo
{
FileName = Assembly.GetEntryAssembly().Location,
Arguments = "-f \"" + file + "\"",
UseShellExecute = false,
CreateNoWindow = true
})
.WaitForExit();
}
static void LoadFile(string inFile)
{
using (var ins = File.OpenText(inFile))
while (ins.Peek() >= 0)
ParseLine(ins.ReadLine());
}
static long[] ParseLine(string line)
{
return line
.Split()
.Skip(1)
.Select(r => (long)(double.Parse(r.Split(':')[1]) * 1000))
.Select(r => r < 0 ? -1 : r)
.ToArray();
}
}
}
【问题讨论】:
-
简化代码,解释实际问题,不要尝试自己处理线程。 TPL 旨在使此类事情变得更容易。也不要拆分字符串,Regex 的速度要快几个数量级 并且 不会生成临时字符串。它快得多,您可能不需要多线程处理。
-
吞吐量可能受到磁盘而不是 CPU 的限制。因此,CPU 正在等待且未完全加载。
-
最后,您的代码是 IO 绑定的,而不是 CPU 绑定的。使用异步方法避免在等待 IO 完成时阻塞线程
-
@harold 这是同一个问题。使用自旋锁达到 100% 的 CPU 利用率有什么意义?还是执行垃圾收集?缓存意味着在一般情况下,多个核心将拥有要处理的数据。也许不是全部,也许一半会加载数据,另一半会处理它
-
最初的想法与@AxelKemper 相同。 I/O 性能通常是此类操作的瓶颈,因此请确保您的磁盘足够快,最好是 SSD。并且不要将线程数限制为内核数(* 2 用于超线程 CPU)。在处理过程中,有时 CPU 会等待数据/指令的内部传输。所以更多的线程意味着更多的 CPU 利用率。哦,当然通常 100% 的利用率并不是最有效的!有些人认为 > 80% 是不可接受的,因为 CPU 资源冲突 = 更长的处理时间
标签: c# .net multithreading performance