gpt4 book ai didi

c# - 使用多个线程创建对象时变慢

转载 作者:太空狗 更新时间:2023-10-29 17:39:37 25 4
gpt4 key购买 nike

我正在做一个产生数百个线程的项目。所有这些线程都处于“休眠”状态(它们被锁定在 Monitor 对象上)。我注意到,如果我增加“休眠”线程的数量,程序就会变慢很多。 “有趣”的是,查看任务管理器似乎线程数越多,处理器越空闲。我已将问题缩小到对象创建。

有人能给我解释一下吗?

我制作了一个小样本来测试它。这是一个控制台程序。它为每个处理器创建一个线程,并通过一个简单的测试(一个“new Object()”)来测量它的速度。不,“new Object()”并没有消失(如果你不相信我,试试看)。主线程显示每个线程的速度。按 CTRL-C,程序会生成 50 个“休眠”线程。减速始于仅 50 个线程。大约 250 时,在任务管理器上非常明显,CPU 未被 100% 使用(在我的上是 82%)。

我已经尝试了三种锁定“休眠”线程的方法:Thread.CurrentThread.Suspend()(不好,不好,我知道 :-)),锁定已锁定的对象和 Thread.Sleep(Timeout.无穷)。一样的。如果我用新的 Object() 注释该行,并将其替换为 Math.Sqrt(或什么都不用),问题就不存在了。速度不随线程数变化。其他人可以检查吗?有谁知道瓶颈在哪里?

啊...您应该在 Release模式下测试它,而不是从 Visual Studio 启动它。我在双处理器(无 HT)上使用 XP sp3。我已经使用 .NET 3.5 和 4.0 对其进行了测试(以测试不同的框架运行时)

namespace TestSpeed
{
using System;
using System.Collections.Generic;
using System.Threading;

class Program
{
private const long ticksInSec = 10000000;
private const long ticksInMs = ticksInSec / 1000;
private const int threadsTime = 50;
private const int stackSizeBytes = 256 * 1024;
private const int waitTimeMs = 1000;

private static List<int> collects = new List<int>();
private static int[] objsCreated;

static void Main(string[] args)
{
objsCreated = new int[Environment.ProcessorCount];
Monitor.Enter(objsCreated);

for (int i = 0; i < objsCreated.Length; i++)
{
new Thread(Worker).Start(i);
}

int[] oldCount = new int[objsCreated.Length];

DateTime last = DateTime.UtcNow;

Console.Clear();

int numThreads = 0;
Console.WriteLine("Press Ctrl-C to generate {0} sleeping threads, Ctrl-Break to end.", threadsTime);

Console.CancelKeyPress += (sender, e) =>
{
if (e.SpecialKey != ConsoleSpecialKey.ControlC)
{
return;
}

for (int i = 0; i < threadsTime; i++)
{
new Thread(() =>
{
/* The same for all the three "ways" to lock forever a thread */
//Thread.CurrentThread.Suspend();
//Thread.Sleep(Timeout.Infinite);
lock (objsCreated) { }
}, stackSizeBytes).Start();

Interlocked.Increment(ref numThreads);
}

e.Cancel = true;
};

while (true)
{
Thread.Sleep(waitTimeMs);

Console.SetCursorPosition(0, 1);

DateTime now = DateTime.UtcNow;

long ticks = (now - last).Ticks;

Console.WriteLine("Slept for {0}ms", ticks / ticksInMs);

Thread.MemoryBarrier();

for (int i = 0; i < objsCreated.Length; i++)
{
int count = objsCreated[i];
Console.WriteLine("{0} [{1} Threads]: {2}/sec ", i, numThreads, ((long)(count - oldCount[i])) * ticksInSec / ticks);
oldCount[i] = count;
}

Console.WriteLine();

CheckCollects();

last = now;
}
}

private static void Worker(object obj)
{
int ix = (int)obj;

while (true)
{
/* First and second are slowed by threads, third, fourth, fifth and "nothing" aren't*/

new Object();
//if (new Object().Equals(null)) return;
//Math.Sqrt(objsCreated[ix]);
//if (Math.Sqrt(objsCreated[ix]) < 0) return;
//Interlocked.Add(ref objsCreated[ix], 0);

Interlocked.Increment(ref objsCreated[ix]);
}
}

private static void CheckCollects()
{
int newMax = GC.MaxGeneration;

while (newMax > collects.Count)
{
collects.Add(0);
}

for (int i = 0; i < collects.Count; i++)
{
int newCol = GC.CollectionCount(i);

if (newCol != collects[i])
{
collects[i] = newCol;
Console.WriteLine("Collect gen {0}: {1}", i, newCol);
}
}
}
}
}

最佳答案

启动 Taskmgr.exe,进程选项卡。查看+选择列,勾选“Page Fault Delta”。您将看到分配数百兆字节的影响,只是为了存储您创建的所有这些线程的堆栈。每当您的进程出现该数字时,您的程序就会阻塞等待操作系统将数据从磁盘分页到 RAM。

TANSTAAFL,天下没有免费的午餐。

关于c# - 使用多个线程创建对象时变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4969963/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com