我使用以下两种方法。名为DoMyWork1的方法确实可以很好地扩展,就像需要6秒才能在3个线程中运行其中的三个。而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);
}
答案 0 :(得分:2)
只有当程序缺乏CPU资源时,线程才能提高程序性能。对于您的程序来说情况并非如此,应该可以从Taskmgr.exe性能选项卡中看到它。这里的资源很慢就是你的硬盘或网卡。 ReadToEnd()调用速度很慢,等待磁盘检索文件数据。您对文件数据执行的任何其他操作都比此快3个数量级。
线程将依次等待磁盘数据。实际上,线程很可能实际上使程序运行得慢得多。它们将导致磁盘驱动器磁头在磁盘上的脱离磁道之间来回跳转,因为每个线程正在使用不同的文件。 真正缓慢的一件事是让头部寻找另一条轨道。对于快速磁盘,通常大约10毫秒。相当于大约50万个CPU指令。
除非获得更快的磁盘,否则无法使程序运行得更快。 SSD很不错。请注意文件系统缓存的影响,第二次运行程序时,从缓存而不是磁盘检索文件数据时,它将运行得非常快。这在生产环境中很少发生。
答案 1 :(得分:0)
所有文件访问都将在操作系统层中成为串行文件并对其进行线程处理将导致您看到的内容。
答案 2 :(得分:0)
我有点惊讶 - 我希望第一次访问这些文件来缓存,然后剩下的访问只是命中内存。所以三个线程不应该比一个线程慢得多。如果您正在写入每个文件,那将会产生影响 - AppendToFile函数究竟做了什么?
答案 3 :(得分:0)
一个问题可能是您要为每个要查找的新字符串打开并阅读每个文件。
如果你改变了foreach循环的顺序并且只根据需要附加到文件会发生什么?
我认为你会看到更好的表现。
理想情况下,如果您可以将文件读取完全取出,那将是最快的。 I / O绑定操作将始终导致在磁盘上等待的上下文切换返回数据。