【发布时间】:2009-05-27 09:22:37
【问题描述】:
我在自己编写的多线程应用程序中看到了一些奇怪的行为,该应用程序不能很好地跨多个内核扩展。
以下代码说明了我看到的行为。看起来堆密集型操作并没有跨多个核心扩展,而是它们似乎变慢了。即使用单线程会更快。
class Program
{
public static Data _threadOneData = new Data();
public static Data _threadTwoData = new Data();
public static Data _threadThreeData = new Data();
public static Data _threadFourData = new Data();
static void Main(string[] args)
{
// Do heap intensive tests
var start = DateTime.Now;
RunOneThread(WorkerUsingHeap);
var finish = DateTime.Now;
var timeLapse = finish - start;
Console.WriteLine("One thread using heap: " + timeLapse);
start = DateTime.Now;
RunFourThreads(WorkerUsingHeap);
finish = DateTime.Now;
timeLapse = finish - start;
Console.WriteLine("Four threads using heap: " + timeLapse);
// Do stack intensive tests
start = DateTime.Now;
RunOneThread(WorkerUsingStack);
finish = DateTime.Now;
timeLapse = finish - start;
Console.WriteLine("One thread using stack: " + timeLapse);
start = DateTime.Now;
RunFourThreads(WorkerUsingStack);
finish = DateTime.Now;
timeLapse = finish - start;
Console.WriteLine("Four threads using stack: " + timeLapse);
Console.ReadLine();
}
public static void RunOneThread(ParameterizedThreadStart worker)
{
var threadOne = new Thread(worker);
threadOne.Start(_threadOneData);
threadOne.Join();
}
public static void RunFourThreads(ParameterizedThreadStart worker)
{
var threadOne = new Thread(worker);
threadOne.Start(_threadOneData);
var threadTwo = new Thread(worker);
threadTwo.Start(_threadTwoData);
var threadThree = new Thread(worker);
threadThree.Start(_threadThreeData);
var threadFour = new Thread(worker);
threadFour.Start(_threadFourData);
threadOne.Join();
threadTwo.Join();
threadThree.Join();
threadFour.Join();
}
static void WorkerUsingHeap(object state)
{
var data = state as Data;
for (int count = 0; count < 100000000; count++)
{
var property = data.Property;
data.Property = property + 1;
}
}
static void WorkerUsingStack(object state)
{
var data = state as Data;
double dataOnStack = data.Property;
for (int count = 0; count < 100000000; count++)
{
dataOnStack++;
}
data.Property = dataOnStack;
}
public class Data
{
public double Property
{
get;
set;
}
}
}
此代码在 Core 2 Quad(4 核系统)上运行,结果如下:
一个线程使用堆:00:00:01.8125000
使用堆的四个线程:00:00:17.7500000
一个线程使用堆栈:00:00:00.3437500
四个线程使用堆栈:00:00:00.3750000
因此,使用具有四个线程的堆完成了 4 倍的工作,但花费了将近 10 倍的时间。这意味着在这种情况下只使用一个线程会快两倍??????
使用堆栈的效果比预期的要好得多。
我想知道这里发生了什么。一次只能从一个线程写入堆吗?
【问题讨论】:
-
它的一切都在那里再看一遍
-
抱歉,滚动条把我扔了:)
-
我只是注意到堆栈和堆循环运行的次数不同,现在正在修复...
-
@Daniel:你在 Visual Studio 中运行过吗?看看我的答案...
-
@Reed:在 Visual Studio 之外运行时差异消失了。但是,请参阅我对您关于启动线程开销的回答的评论。