gpt4 book ai didi

c# - 如何在多线程应用程序中实现100%的CPU使用率?

转载 作者:行者123 更新时间:2023-12-03 12:54:37 26 4
gpt4 key购买 nike

我有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();
}
}
}

最佳答案

终于,我找到了瓶颈。我正在使用string.Split来解析每行数据中的数字,因此我得到了数十亿个短字符串。这些字符串被放入堆中。由于所有线程共享一个堆内存,因此内存分配是同步的。由于进程具有单独的堆-不会发生同步,并且工作很快。那是问题的根源。因此,我重写了使用IndexOf而不是Split进行的解析,并且线程开始比单独的进程执行得更好。就像我期望的那样。

由于.NET没有默认工具可以从字符串中的特定位置解析实数,因此我使用了以下代码:https://codereview.stackexchange.com/questions/75791/optimize-custom-double-parse,进行了少量修改。

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

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)
{
Parallel.ForEach(
Directory.EnumerateFiles(folder),
new ParallelOptions { MaxDegreeOfParallelism = 12 },
f => algorithm(f));
}

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)
{
// first, count number of items
var items = 1;
for (var i = 0; i < line.Length; i++)
if (line[i] == ' ') items++;

//allocate memory and parse items
var all = new long[items];
var n = 0;
var index = 0;
while (index < line.Length)
{
var next = line.IndexOf(' ', index);
if (next < 0) next = line.Length;
if (next > index)
{
var v = (long)(parseDouble(line, line.IndexOf(':', index) + 1, next - 1) * 1000);
if (v < 0) v = -1;
all[n++] = v;

}
index = next + 1;
}

return all;
}

private readonly static double[] pow10Cache;
static Program()
{
pow10Cache = new double[309];

double p = 1.0;
for (int i = 0; i < 309; i++)
{
pow10Cache[i] = p;
p /= 10;
}
}

static double parseDouble(string input, int from, int to)
{
long inputLength = to - from + 1;
long digitValue = long.MaxValue;
long output1 = 0;
long output2 = 0;
long sign = 1;
double multiBy = 0.0;
int k;

//integer part
for (k = 0; k < inputLength; ++k)
{
digitValue = input[k + from] - 48; // '0'

if (digitValue >= 0 && digitValue <= 9)
{
output1 = digitValue + (output1 * 10);
}
else if (k == 0 && digitValue == -3 /* '-' */)
{
sign = -1;
}
else if (digitValue == -2 /* '.' */ || digitValue == -4 /* ',' */)
{
break;
}
else
{
return double.NaN;
}
}

//decimal part
if (digitValue == -2 /* '.' */ || digitValue == -4 /* ',' */)
{
multiBy = pow10Cache[inputLength - (++k)];

for (; k < inputLength; ++k)
{
digitValue = input[k + from] - 48; // '0'

if (digitValue >= 0 && digitValue <= 9)
{
output2 = digitValue + (output2 * 10);
}
else
{
return Double.NaN;
}
}

multiBy *= output2;
}

return sign * (output1 + multiBy);
}
}
}

关于c# - 如何在多线程应用程序中实现100%的CPU使用率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44324264/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com