使用Delegate进行异步调用

时间:2015-05-19 05:31:11

标签: c# asynchronous delegates

我希望方法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);
     }
}

2 个答案:

答案 0 :(得分:3)

您的代码并不需要任何多线程。它甚至不需要异步处理 - 您最有可能使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

答案 1 :(得分:1)

您不需要调用EndInvoke,实际上所有EndInvoke都会等待您的返回值。由于SplitFile返回无效,我的猜测是有一个优化,因为你不需要等待任何东西,它只是忽略了等待。有关详细信息:C# Asynchronous call without EndInvoke?

话虽如此,您对Begin / EndInvoke的使用可能不会比串行编程更快(并且可能会稍微慢一点),因为您的for循环仍然是序列化的,并且您仍然在串行运行迭代。所有改变的是你使用代表看起来似乎没有必要。

你打算使用的是Parallel.ForEach(MSDN:https://msdn.microsoft.com/en-us/library/dd992001(v=vs.110).aspx),这可能会并行运行迭代。

编辑:正如其他人所提到的,让多个线程参与文件操作可能无法提高性能,因为您的文件操作可能是磁盘绑定的。从异步文件读/写中获得的主要好处可能是取消阻止UI更新的主线程。你需要指定你想要的东西&#34;表现&#34;如果你想要一个更好的答案。