编写一个将文件目录作为输入的查找最大方法。循环通过目录文件并搜索100 + rnd之后的最大值。但是我有很多文件,所以需要一段时间。加快速度的最佳方法是什么?不太确定最好的解决方案。可能是一种线程池?这就是我所拥有的。另外,请假设该行在转换为int之前已经过验证。感谢。
编辑:文件的每一行都有一个int。不仅每个文件一个。 编辑2:操作目前约为900毫秒,理想情况下需要降低400%。
public static int FindLargest()
{
var files = Directory.GetFiles(@"C:\Dir");
List<int> values = new List<int>();
foreach (var fileName in files)
{
var file = File.ReadAllLines(fileName);
foreach(var line in file)
{
int product = PerformAddition(Convert.ToInt32(line));
if(product >= 100) values.Add(product);
}
}
int largest = 0;
foreach(int value in values)
{
if(value > largest) largest = value;
}
return largest;
}
public static int PerformAddition(int value)
{
var rnd = new Random();
return value + rnd.Next(0, 100);
}
答案 0 :(得分:3)
所以前提是再次测试原始版本的其他一些解决方案
测试进行了100多个文件并运行10次。比例是文件中的多少行内容
最后,我删除了随机,以便我可以验证结果
Mode : Release
Test Framework : .NET Framework 4.7.1
Benchmarks runs : 10 times (averaged)
Scale : 100
Name | Average | Fastest | StDv | Cycles | Pass
-----------------------------------------------------------------
Mine4 | 2.323 ms | 2.191 ms | 0.13 | 2,241,488 | Yes
johnPlusMine | 2.676 ms | 2.064 ms | 0.33 | 6,117,891 | Yes
john | 3.124 ms | 2.723 ms | 0.27 | 8,914,485 | Yes
Original | 10.004 ms | 9.146 ms | 0.71 | 34,025,586 | Base
Mine3 | 10.279 ms | 7.012 ms | 2.45 | 31,679,870 | Yes
Scale : 1,000
Name | Average | Fastest | StDv | Cycles | Pass
-------------------------------------------------------------------
Mine4 | 4.037 ms | 3.363 ms | 0.45 | 2,566,176 | Yes
johnPlusMine | 4.606 ms | 3.040 ms | 1.61 | 10,893,833 | Yes
john | 8.307 ms | 7.118 ms | 0.70 | 18,582,130 | Yes
Mine3 | 11.023 ms | 9.498 ms | 1.61 | 37,394,603 | Yes
Original | 33.316 ms | 23.887 ms | 8.29 | 108,467,775 | Base
Scale : 10,000
Name | Average | Fastest | StDv | Cycles | Pass
---------------------------------------------------------------------
johnPlusMine | 12.643 ms | 11.908 ms | 0.62 | 21,985,225 | Yes
Mine4 | 12.655 ms | 11.074 ms | 1.00 | 2,482,408 | Yes
Mine3 | 38.223 ms | 37.495 ms | 0.83 | 130,130,301 | Yes
john | 53.337 ms | 47.496 ms | 3.79 | 126,151,357 | Yes
Original | 194.628 ms | 185.462 ms | 9.20 | 660,359,390 | Base
Scale : 100,000
Name | Average | Fastest | StDv | Cycles | Pass
----------------------------------------------------------------------------
johnPlusMine | 195.336 ms | 179.742 ms | 12.09 | 166,869,434 | Yes
Mine4 | 209.209 ms | 180.388 ms | 22.50 | 3,220,582 | Yes
Mine3 | 331.211 ms | 313.332 ms | 19.35 | 1,097,353,237 | Yes
john | 489.939 ms | 455.913 ms | 26.35 | 910,277,113 | Yes
Original | 2,877.904 ms | 2,845.898 ms | 31.42 | 9,584,556,134 | Base
基本上这是使用指针和手动解析的unsafe
fixed
版本
protected override unsafe int InternalRun()
{
var largest = int.MinValue;
var files = Directory.GetFiles(@"D:\ints");
foreach (var file in files)
{
var content = File.ReadAllText(file);
fixed (char* pContent = content)
{
var len = pContent + content.Length;
var current = 0;
for (var p = pContent; p < len; p++)
{
if (*p >= 48)
{
current = current * 10 + *p - 48;
}
else
{
if (current > largest)
{
largest = current;
}
current = 0;
p++;
}
}
current = 0;
if (current > largest)
{
largest = current;
}
}
}
return largest;
}
这使用ActionBlocks
和unsafe
private static volatile int _max = int.MinValue;
private static readonly object _sync = new object();
public static async Task<int> DoWorkLoads(string[] files)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 50
};
var block = new ActionBlock<string>((Action<string>)MyMethodAsync, options);
foreach (var file in files)
{
block.Post(file);
}
block.Complete();
await block.Completion;
return _max;
}
unsafe public static void MyMethodAsync(string fileName)
{
var largest = int.MinValue;
var content = File.ReadAllText(fileName);
fixed (char* pContent = content)
{
var len = pContent + content.Length;
var current = 0;
for (var p = pContent; p < len; p++)
{
if (*p >= 48)
{
current = current * 10 + *p - 48;
}
else
{
if (current > largest)
{
largest = current;
}
current = 0;
p++;
}
}
current = 0;
if (current > largest)
{
largest = current;
}
}
lock (_sync)
{
if (largest > _max)
{
_max = largest;
}
}
}
protected override int InternalRun()
{
_max = 0;
var files = Directory.GetFiles(@"D:\ints");
var result = DoWorkLoads(files)
.Result;
return result;
}
private static object _sync = new object();
private static int _max;
public static unsafe void MyMethodAsync(string fileName)
{
var largest = int.MinValue;
var content = File.ReadAllText(fileName);
fixed (char* pContent = content)
{
var len = pContent + content.Length;
var current = 0;
for (var p = pContent; p < len; p++)
{
if (*p >= 48)
{
current = current * 10 + *p - 48;
}
else
{
if (current > largest)
{
largest = current;
}
current = 0;
p++;
}
}
current = 0;
if (current > largest)
{
largest = current;
}
}
lock (_sync)
{
if (largest > _max)
{
_max = largest;
}
}
}
protected override int InternalRun()
{
var files = Directory.GetFiles(@"D:\ints");
Parallel.ForEach(files, MyMethodAsync);
return _max;
}
我的其他尝试是使用async
await
和动作块,其想法是让IO绑定任务成为IO绑定任务,但结果并不公平。最后,如果我使用Parallel.ForEarch
,我可能会获得更快的速度,但是我的能量耗尽了。
无论如何,如果你要使用不安全的版本,你需要设置项目在属性中使用不安全的代码,也没有错误检查,所以如果你输入垃圾它将输出垃圾。此外,您可能想要调整MaxDegreeOfParallelism以获得最大的效果。
老实说,你可能更好地与约翰回答,除非你试图挤出最后一点表现,否则它更直接
这样做
// var content = File.ReadAllLines(file);
基本上,您正在阅读文件的内容,无明显原因
答案 1 :(得分:1)
你可以像这样重写它:
public static int FindLargest()
{
var files = Directory.GetFiles(@"C:\Dir");
int largest = 0;
Object lockObject = new object();
Parallel.ForEach(files, file =>
{
foreach (var line in File.ReadLines(file))
{
int product = PerformAddition(Convert.ToInt32(line));
if (product < 100)
{
continue;
}
if (product > largest)
{
lock(lockObject)
{
if (product > largest)
{
largest = product;
}
}
}
}
});
return largest;
}
它并行运行每个文件,并枚举行而不是将它们全部加载到内存中。由于您只想要最大的值,因此我避免将值存储在内存中,以便随时跟踪最大值。
对于文件的每一行我们:
largest
。最后,我们返回最大值。
由于Random
类默认使用当前系统时间的种子进行初始化,因此您可能会获得重复的随机值。我已经编写了一些代码,这些代码将为每个线程创建一个新的Random
实例(因为我的方法是多线程的。如果你使用非多线程方法,你可以只使用一个{{{ 1}}):
Random
在我的系统测试中(SSD,i7 4770k),我可以在750毫秒内始终处理100个文件,总大小约为75兆字节。就行而言,它每毫秒约为7500行。