使用委托的异步调用
本文关键字:异步 调用 | 更新日期: 2023-09-27 17:49:36
我希望方法splitFile
的单独异步线程应该运行,以便任务将变得更快,但下面的代码不工作。当我调试时,它到达RecCnt = File.ReadAllLines(SourceFile).Length - 1;
行并出来。请帮助。
public delegate void SplitFile_Delegate(FileInfo file);
static void Main(string[] args)
{
DirectoryInfo d = new DirectoryInfo(@"D:'test'Perf testing Splitter"); //Assuming Test is your Folder
FileInfo[] Files = d.GetFiles("*.txt"); //Getting Text files
foreach (FileInfo file in Files)
{
SplitFile_Delegate LocalDelegate = new SplitFile_Delegate(SplitFile);
IAsyncResult R = LocalDelegate.BeginInvoke(file, null, null); //invoking the method
LocalDelegate.EndInvoke(R);
}
}
private static void SplitFile(FileInfo file)
{
try
{
String fname;
//int FileLength;
int RecCnt;
int fileCount;
fname = file.Name;
String SourceFile = @"D:'test'Perf testing Splitter'" + file.Name;
RecCnt = File.ReadAllLines(SourceFile).Length - 1;
fileCount = RecCnt / 10000;
FileStream fs = new FileStream(SourceFile, FileMode.Open);
using (StreamReader sr = new StreamReader(fs))
{
while (!sr.EndOfStream)
{
String dataLine = sr.ReadLine();
for (int x = 0; x < (fileCount + 1); x++)
{
String Filename = @"D:'test'Perf testing Splitter'Destination Files'" + fname + "_" + x + "by" + (fileCount + 1) + ".txt"; //test0by4
using (StreamWriter Writer = file.AppendText(Filename))
{
for (int y = 0; y < 10000; y++)
{
Writer.WriteLine(dataLine);
dataLine = sr.ReadLine();
}
Writer.Close();
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
您的代码实际上并不需要任何多线程。它实际上甚至不需要那么多的异步处理——你很可能会使I/O饱和,除非你有多个驱动器作为数据源,否则你不会通过增加并行性来改善这一点。
另一方面,代码对每个文件读取两次。毫无理由地浪费内存、时间甚至CPU。相反,只需这样做:FileStream fs = new FileStream(SourceFile, FileMode.Open);
using (StreamReader sr = new StreamReader(fs))
{
string line;
string fileName = null;
StreamWriter outputFile = null;
int lineCounter = 0;
int outputFileIndex = 0;
while ((line = sr.ReadLine()) != null)
{
if (fileName == null || lineCounter >= 10000)
{
lineCounter = 0;
outputFileIndex++;
fileName = @"D:'Output'" + fname + "_" + outputFileIndex + ".txt";
if (outputFile != null) outputFile.Dispose();
outputFile = File.AppendText(fileName);
}
outputFile.WriteLine(line);
lineCounter++;
}
}
如果你真的需要XOutOfY
格式的文件名,你可以在之后重新命名它们-这比阅读源文件两次,一行接一行便宜得多。或者,如果您不关心一次将整个文件保存在内存中,则只需使用从ReadAllLines
获得的数组并对其进行迭代,而不是重新进行读取。
为了使这更容易,您还可以使用foreach (var line in File.ReadLines(fileName))
。
如果你真的想让它异步,处理它的方法是使用异步I/O,而不仅仅是假脱机新线程。所以你可以使用await
和StreamReader.ReadLineAsync
等
您不需要调用EndInvoke,实际上所有EndInvoke所做的就是等待返回值。由于SplitFile返回void,我猜测这是一个优化,因为你不需要等待任何东西,它只是忽略了等待。了解更多细节:没有EndInvoke的c#异步调用?
也就是说,使用Begin/EndInvoke可能不会比串行编程快(而且可能会稍微慢一点),因为for循环仍然是串行的,并且仍然以串行方式运行迭代。唯一改变的是你使用了一个委托而它看起来是不必要的。
有可能你想用的是Parallel。ForEach (MSDN: https://msdn.microsoft.com/en-us/library/dd992001(v=vs.110).aspx),它可能会并行运行迭代。
编辑:正如其他人提到的,有多个线程参与文件操作可能不会提高性能,因为文件操作可能是磁盘绑定的。从异步文件读/写中获得的主要好处可能是为UI更新解除主线程阻塞。如果你想要一个更好的答案,你需要指定你想要的"性能"。