1

我正在使用以下两种方法。名为 DoMyWork1 的方法确实可以很好地扩展,就像在 3 个线程中运行其中的三个需要 6 秒。而 DoMyJob 方法根本无法扩展。如果一个线程需要 4 秒,那么运行 3 个线程需要 13 秒。我究竟做错了什么?文件读取和/或写入是否需要线程池以外的特殊线程处理?

我的呼叫代码

public static void Process(MyDelegate md , int threads)
{
    int threadcount = threads;

    ManualResetEvent[] doneEvents = new ManualResetEvent[threadcount];

    DateTime dtstart = DateTime.Now;

    List<string> myfiles = GetMyFiles(@"c:\");


    for (int i = 0; i < threadcount; i++)
    {

        doneEvents[i] = new ManualResetEvent(false);
        MyState ms = new MyState();
        ms.ThreadIndex = i;
        ms.EventDone = doneEvents[i];
        ms.files = myfiles;
        ThreadPool.QueueUserWorkItem(md.Invoke, ms);
    }


    WaitHandle.WaitAll(doneEvents);

    DateTime dtend = DateTime.Now;
    TimeSpan ts = dtend - dtstart;
    Console.WriteLine("All complete in {0} seconds.", ts.ToString());
    Console.ReadLine();

}

public static void DoMyWork1(Object threadContext)
{
    MyState st = (MyState)threadContext;
    Console.WriteLine("thread {0} started...", st.ThreadIndex);

    Thread.Sleep(5000);

    Console.WriteLine("thread {0} finished...", st.ThreadIndex);
    st.EventDone.Set();
}



private static void DoMyJob(MyState st)
{
    Console.WriteLine("I am in thread {0} started...", st.ThreadIndex);


    string[] mystrings = new string[] { "one", "two", "three" };

    foreach (string s in mystrings)
    {
        foreach (string file in st.files)
        {
            if (!(new StreamReader(file).ReadToEnd().Contains(s)))
            {
                AppendToFile(String.Format("{0} word searching in file {1} in thread {2}", s, file, st.ThreadIndex));
            }


        }
    }

    Console.WriteLine("I am in thread {0} ended...", st.ThreadIndex);
}
4

4 回答 4

2

只有当程序缺乏 CPU 资源时,线程才能提高程序性能。您的程序并非如此,它应该可以从 Taskmgr.exe 性能选项卡中轻松看到。这里的慢资源是您的硬盘或网卡。ReadToEnd() 调用非常缓慢,等待磁盘检索文件数据。您对文件数据执行的任何其他操作都比这快 3 个数量级。

线程将依次等待磁盘数据。事实上,线程很有可能会让你的程序运行得更慢。它们将导致磁盘驱动器磁头在磁盘上不相交的磁道之间来回跳转,因为每个线程都在处理不同的文件。真正慢的一件事是导致磁头寻找另一个轨道。快速磁盘通常需要大约 10 毫秒。相当于大约 50 万条 CPU 指令。

除非您获得更快的磁盘,否则您无法使程序运行得更快。SSD 不错。注意文件系统缓存的影响,第二次运行程序时,当从缓存而不是磁盘中检索文件数据时,它将运行得非常快。这在生产环境中很少发生。

于 2009-12-13T12:10:54.527 回答
0

所有文件访问都将在 OS 层中串行化,并且将其线程化将得到您所看到的结果。

于 2009-12-13T04:47:24.413 回答
0

我有点惊讶 - 我希望对这些文件的第一次访问会缓存,然后剩余的访问只会命中内存。所以三个线程不应该比一个慢太多。如果您正在写入每个文件,那会有所不同 - AppendToFile 函数究竟是做什么的?

于 2009-12-13T05:30:21.190 回答
0

一个问题可能是您正在打开和读取每个文件,对于您正在寻找的每个新字符串。

如果您切换 foreach 循环的顺序并仅根据需要附加到文件中会发生什么?

我想你会看到更好的表现。

理想情况下,如果您可以将文件读取完全排除在循环之外,那将是最快的。I/O 绑定操作总是会导致在磁盘上等待返回数据的上下文切换。

于 2009-12-13T05:40:52.740 回答