通过写入文件系统进行线程化

时间:2015-01-21 15:07:31

标签: c#

我有这个。这是一个生成银行账户的申请

static void Main(string[] args)
    {

        string path = @"G:\BankNumbers";
        var bans = BankAcoutNumbers.BANS;
        const int MAX_FILES = 80;
        const int BANS_PER_FILE = 81818182/80;
        int bansCounter = 0;
        var part = new List<int>();
        var maxNumberOfFiles = 10;
        Stopwatch timer = new Stopwatch();
        var fileCounter = 0;


        if (!Directory.Exists(path))
        {
            DirectoryInfo di = Directory.CreateDirectory(path);
        }

        try
        {
            while (fileCounter <= maxNumberOfFiles)
            {
                timer.Start();
                foreach (var bank in BankAcoutNumbers.BANS)
                {
                    part.Add(bank);
                    if (++bansCounter >= BANS_PER_FILE)
                    {
                        string fileName = string.Format("{0}-{1}", part[0], part[part.Count - 1]);
                        string outputToFile = "";// Otherwise you dont see the lines in the file. Just single line!!

                        Console.WriteLine("NR{0}", fileName);
                        string subString = System.IO.Path.Combine(path, "BankNumbers");//Needed to add, because otherwise the files will not stored in the correct folder!!
                        fileName =  subString + fileName;

                        foreach (var partBan in part)
                        {

                            Console.WriteLine(partBan);
                            outputToFile += partBan + Environment.NewLine;//Writing the lines to the file

                        }
                        System.IO.File.WriteAllText(fileName, outputToFile);//Writes to file system.
                        part.Clear();
                        bansCounter = 0;
                        //System.IO.File.WriteAllText(fileName, part.ToString());

                        if (++fileCounter >= MAX_FILES)
                            break;
                    }
                }
            }

            timer.Stop();
            Console.WriteLine(timer.Elapsed.Seconds);
        }
        catch (Exception)
        {

            throw;
        }

        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }

但是,这产生了8100万个银行账户记录,分成80个文件。但是我可以通过线程来加速这个过程吗?

2 个答案:

答案 0 :(得分:1)

您正在谈论加快进程,其进程的瓶颈很可能是文件写入速度。您无法真正有效地将写入并行化到单个磁盘。

如果您生成一个只负责fileIO的工作线程,那么可能会看到速度略有提高。换句话说,创建一个缓冲区,让主线程将内容转储到其中,而另一个线程将其写入磁盘。它是经典的生产者/消费者动态。但是,我不会期待严重的速度提升。

另外请记住,写入控制台会降低你的速度,但你可以把它保留在主线程中,你可能会没事的。只需确保对缓冲区大小设置限制,并在缓冲区已满时让生产者线程挂起。

编辑:另外看一下L-Three提供的链接,使用 BufferedStream 会有所改进(并且可能无需渲染消费者线程)

答案 1 :(得分:0)

您的流程可分为两个步骤:

  1. 生成帐户
  2. 将帐户保存在文件
  3. 第一步可以并行完成,因为帐户之间没有依赖关系。这就是创建一个帐号xyz,您不必依赖帐户xyz - 1中的数据(因为它可能尚未创建)。

    有问题的位是将数据写入文件。您不希望多个线程尝试访问和写入同一文件。添加锁定可能会使您的代码成为维护的噩梦。其他问题是它写入文件会减慢整个过程。

    目前,在您的代码中创建帐户并在一个进程中写入文件。

    您可以尝试分离这些过程。首先,您创建所有帐户并将其保留在某个集合中。这里可以安全地使用多线程。只有在创建了所有帐户后才能保存它们。

    改善储蓄过程将需要更多的工作。您必须将所有帐户划分为8个单独的集合。对于每个集合,您将创建一个单独的文件然后,您可以获取第一个集合,第一个文件,并创建一个将数据写入文件的线程。第二个集合和第二个文件相同。等等。这8个进程可以并行运行,您不必担心多个线程会尝试访问同一个文件。

    下面是一些伪代码来说明这个想法:

        public void CreateAndSaveAccounts()
        {
            List<Account> accounts = this.CreateAccounts();
    
            // Divide the accounts into separate batches
            // Of course the process can (and shoudl) be automated.
            List<List<Account>> accountsInSeparateBatches =
                new List<List<Account>>
                {
                    accounts.GetRange(0, 10000000),             // Fist batch of 10 million
                    accounts.GetRange(10000000, 10000000),      // Second batch of 10 million
                    accounts.GetRange(20000000, 10000000)       // Third batch of 10 million
                    // ...
                };
    
            // Save accounts in parallel
            Parallel.For(0, accountsInSeparateBatches.Count,
                i =>
                    {
                        string filePath = string.Format(@"C:\file{0}", i);
                        this.SaveAccounts(accountsInSeparateBatches[i], filePath);
                    }
                );
        }
    
        public List<Account> CreateAccounts()
        {
            // Create accounts here
            // and return them as a collection.
            // Use parallel processing wherever possible
        }
    
        public void SaveAccounts(List<Account> accounts, string filePath)
        {
            // Save accounts to file
            // The method creates a thread to do the work.
        }