1

有一个按某些条件对大 txt 文件进行排序的应用程序。例如,我需要启动 5 个线程,但我使用 foreach 循环从文件中逐行读取。如果我用我的代码启动 5 个线程,所有线程都将采用相同的行。

这是我启动 1 个线程的代码:

    Thread[] thr;
    private void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;
        button4.Enabled = true;
        decimal value = 1;
        int i = 0;
        int j = (int)(value);
        thr = new Thread[j];
        for (; i < j; i++)
        {
            thr[i] = new Thread(new ThreadStart(go));
            thr[i].IsBackground = true;
            thr[i].Start();
        }
    }

    private static IEnumerable<string> ReadLineFromFile(TextReader fileReader)
    {
        using (fileReader)
        {
            string currentLine;
            while ((currentLine = fileReader.ReadLine()) != null)
            {
                yield return currentLine;
            }
        }
    }


    public void go()
    {
        while (true)
        {
            TextReader readFile = new StreamReader(file_path, System.Text.Encoding.UTF8, true);
            foreach (string line in ReadLineFromFile(readFile))
            {
                if (line.Split(':')[0].Contains("@"))
                {
                    string out_line = line.Split(':')[0].Replace("+", "") + ":" + line.Split(':')[1];
                    lock (locker)
                    {
                        mail_count++;
                        log_mail(mail_count);
                        mail.Add(out_line.Trim().Replace(";", ":"));
                    }
                }
                else
                {
                    string out_line = line.Split(':')[0].Replace("+", "") + ":" + line.Split(':')[1];
                    lock (locker)
                    {
                        rubbish_count++;
                        log_rubbish(rubbish_count);
                        rubbish.Add(out_line.Trim());
                    }
                }
            }
            MessageBox.Show("Ready");
            BeginInvoke(
            new MethodInvoker(() =>
            {
                button1.Enabled = true;
                button4.Enabled = false;
            }));
            break;
        }
    }
4

3 回答 3

4

所有线程都读取同一个文件是没有用的,从共享文件中读取既困难又低效。

在您的主要功能中,您需要以下内容:

Parallel.ForEach(System.IO.File.ReadLines(file_path, System.Text.Encoding.UTF8), 
   line => ProcessOneLine(line) 
);

然后 ProcessOneLine 会做.Split(':')等等。

于 2013-06-05T09:49:34.177 回答
3

为什么不采用通常的生产者-消费者模式呢?让一个线程读取文件,将行放入某个共享集合中,其他线程只是从集合中挑选数据并进行处理。

更多 - 您可以从文件中读取并为每一行创建Task将负责处理该行并将结果放入输出集合中。

这似乎比 5 个线程尝试读取同一个文件而不是多次读取同一行要好。

于 2013-06-05T09:49:30.690 回答
0

我想确认并扩展 Pako 所说的话。其他线程应该使用来自包含数据的共享集合中的数据并对其进行处理。

让多个线程访问文本文件听起来可能会发生竞争条件。如果一个线程正在更改文件,而另一个线程正在读取该文件,则可能会发生本质上不可预测的结果。

过去,我在使用访问同一文本文件的多个线程时也经历过 BSOD,并且可以推荐反对它。但是,如果您坚持这样做,我建议您查看“lock”关键字和单例设计模式。这将允许您确保一次只有一个线程在访问该文件。

相关链接:

http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.80).aspx http://en.wikipedia.org/wiki/Singleton_pattern

http://en.wikipedia.org/wiki/Double-checked_locking

于 2013-06-05T10:35:35.730 回答