模拟稳定的 CPU 负载和峰值

问题描述 投票:0回答:5

如何在 C# 中生成稳定的 CPU 负载,在一段时间内低于 100%?我还希望能够在一段时间后更改负载量。您建议如何在很短的时间内产生使用高峰?

c# cpu-usage
5个回答
60
投票

首先,您必须了解 CPU 使用率始终是特定时间内的平均值。在任何给定时间,CPU 要么工作,要么不工作。 CPU 永远不会工作到 40%。

但是,我们可以通过让 CPU 工作 0.4 秒并休眠 0.6 秒来模拟一秒钟内 40% 的负载。这使得该秒的平均利用率为 40%。

将其减少到小于一秒,例如 100 毫秒的块应该会提供更稳定的利用率。

以下方法将采用所需利用率的参数,然后将单个 CPU/核心利用到该程度:

public static void ConsumeCPU(int percentage)
{
    if (percentage < 0 || percentage > 100)
        throw new ArgumentException("percentage");
    Stopwatch watch = new Stopwatch();
    watch.Start();            
    while (true)
    {
        // Make the loop go on for "percentage" milliseconds then sleep the 
        // remaining percentage milliseconds. So 40% utilization means work 40ms and sleep 60ms
        if (watch.ElapsedMilliseconds > percentage)
        {
            Thread.Sleep(100 - percentage);
            watch.Reset();
            watch.Start();
        }
    }
}

我在这里使用stopwatch,因为它比TickCount属性更准确,但您同样可以使用它并使用减法来检查您是否跑了足够长的时间。

要记住两件事:

  • 在多核系统上,您必须为每个核心生成一个线程。否则,您将看到仅使用一个 CPU/核心,给出大致的“百分比/核心数”利用率。
  • Thread.Sleep 不太准确。它永远无法保证时间精确到毫秒,因此您会看到结果存在一些变化

要回答您的第二个问题,关于在一段时间后更改利用率,我建议您在一个或多个线程上运行此方法(取决于核心数量),然后当您想要更改利用率时,只需停止这些线程并生成新的线程即可具有新百分比值的。这样,您就不必实现线程通信来更改正在运行的线程的

percentage


19
投票

除了 Isak 响应之外,我在这里提供了一个简单的多核实现:

 public static void CPUKill(object cpuUsage)
    {
        Parallel.For(0, 1, new Action<int>((int i) =>
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            while (true)
            {
                if (watch.ElapsedMilliseconds > (int)cpuUsage)
                {
                    Thread.Sleep(100 - (int)cpuUsage);
                    watch.Reset();
                    watch.Start();
                }
            }
        }));

    }

    static void Main(string[] args)
    {
        int cpuUsage = 50;
        int time = 10000;
        List<Thread> threads = new List<Thread>();
        for (int i = 0; i < Environment.ProcessorCount; i++)
        {
            Thread t = new Thread(new ParameterizedThreadStart(CPUKill));
            t.Start(cpuUsage);
            threads.Add(t);
        }
        Thread.Sleep(time);
        foreach (var t in threads)
        {
            t.Abort();
        }
   }

5
投票

为了统一强调:Isak Savo 的答案略有调整。这个问题很有趣。实际上,有些工作负载在使用的瓦数、热输出、通道饱和度等方面远远超过它,并且可能使用循环,因为工作负载很差并且几乎不切实际。

int percentage = 80;
for (int i = 0; i < Environment.ProcessorCount; i++)
{
    (new Thread(() =>
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        while (true)
        {
            // Make the loop go on for "percentage" milliseconds then sleep the 
            // remaining percentage milliseconds. So 40% utilization means work 40ms and sleep 60ms
            if (watch.ElapsedMilliseconds > percentage)
            {
                Thread.Sleep(100 - percentage);
                watch.Reset();
                watch.Start();
            }
        }
    })).Start();
}

1
投票

每次都必须设置 cpuUsageIncreaseby 变量。 例如:

1- Cpu % 增加 > cpuUsageIncreaseby % 一分钟。 2- 降低至 0%,持续 20 秒。 3- 转到步骤 1。

     private void test()
        {
            int cpuUsageIncreaseby = 10;
            while (true)
            {
                for (int i = 0; i < 4; i++)
                {
                    //Console.WriteLine("am running ");
                    //DateTime start = DateTime.Now;
                    int cpuUsage = cpuUsageIncreaseby;
                    int time = 60000; // duration for cpu must increase for process...
                    List<Thread> threads = new List<Thread>();
                    for (int j = 0; j < Environment.ProcessorCount; j++)
                    {
                        Thread t = new Thread(new ParameterizedThreadStart(CPUKill));
                        t.Start(cpuUsage);
                        threads.Add(t);
                    }
                    Thread.Sleep(time);
                    foreach (var t in threads)
                    {
                        t.Abort();
                    }

                    //DateTime end = DateTime.Now;
                    //TimeSpan span = end.Subtract(start);
                    //Console.WriteLine("Time Difference (seconds): " + span.Seconds);

                    //Console.WriteLine("10 sec wait... for another.");
                    cpuUsageIncreaseby = cpuUsageIncreaseby + 10;
                    System.Threading.Thread.Sleep(20000);
                }
            }
        }

0
投票

分享我自己使用的代码。在尝试了不同的选项之后,我最终得到了下面的结果。重要提示是,我在 Asp.Net core 应用程序中使用了这段代码,它不允许使用 .Abort() 方法;

        [HttpGet("load-cpu")]
        public IActionResult LoadCpu([FromQuery] int percent, [FromQuery] int seconds)
        {
            int iterations = Environment.ProcessorCount;
            ThreadLaunchOptions input = new ThreadLaunchOptions(percent, seconds);
            for (int i = 0; i < iterations; i++)
            {
                    var thread = new Thread(() => GenerateCPULoad(input));
                    thread.Start();
            }

            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            return Ok();
        }

        private void GenerateCPULoad(object loadInput)
        {            
            ThreadLaunchOptions input = loadInput as ThreadLaunchOptions;
            var endTime = DateTime.Now.AddSeconds(input.Seconds); // Adjust duration as needed
            int timeThreshold = input.Percents * 10;
            Stopwatch sw = Stopwatch.StartNew();
            while (DateTime.Now < endTime)
            {
                //1000 60*10
                while(sw.ElapsedMilliseconds < timeThreshold)
                {
                    _ = Math.Sqrt(10 * this.GetHashCode()) ;
                }

                int timeLeft = 1000 - timeThreshold;
                if (timeLeft > 0)
                {
                    Thread.Sleep(timeLeft);
                    sw.Reset();
                    sw.Start();
                }
            }
            sw.Stop();
        }
        



        private record ThreadLaunchOptions(int Percents, int Seconds);

当您有上面的代码时,您可以调用端点并在特定时间创建漂亮的普通 CPU 负载。例如:

http://localhost:5000/load-cpu?percent=40&秒=20

© www.soinside.com 2019 - 2024. All rights reserved.