Синусоидальная загрузка ЦП для контроля языка Go | Месяц темы Go

Go

источник темы

В первом заголовке «Красота программирования» исходный текст дает решение языка C, связанные с ним функциональные интерфейсы и инструменты. Думаете, как использовать Go для достижения этой цели?

Напишите программу, которая позволяет пользователю определять загрузку ЦП диспетчера задач Windows. Возможны следующие три ситуации:

  1. Использование ЦП фиксируется на уровне 50%, что является прямой линией;
  2. Коэффициент занятости ЦП представляет собой прямую линию, но конкретный коэффициент занятости определяется параметрами командной строки (1~100);
  3. Состояние занятости ЦП представляет собой синусоидальную кривую
  4. Если ваш компьютер двухъядерный, каким будет результат вашей программы и почему?

Решения:

Мысль: Как сделать загрузку процессора 50%? Мы считаем, что обычно есть два подхода:

  1. ЦП работает все время, но скорость/частота составляет 50% от полной скорости.
  2. ЦП разделен по времени, работает на полной скорости 50% времени и не работает 50% времени.

Зачем отказываться от идеи 1: настроить частоту процессора

(1) Частота ЦП связана с тактовым циклом ЦП, и необходимо получить дополнительную аппаратную поддержку, а не программную перспективу.

(2) Это не обязательно универсально.Например, метод регулировки частоты процессора процессора Intel отличается от метода других марок, и поддержка разных серий процессоров также отличается, и набор инструкций также отличается .

(3) Управление частотой ЦП требует более высоких разрешений на выполнение программы, таких как права root

(4) Конечно, нельзя сказать, что такое мышление совершенно невозможно.cpufrequtilsОн поддерживает настройку режима работы ЦП. Существует режим «пользовательское пространство», то есть определяемый пользователем режим, который используется пользовательскими приложениями для настройки рабочей частоты ЦП. Студенты, заинтересованные в этой идее, могут попытайся.

(5) Основная причина заключается в том, что когда мы ограничиваем частоту ЦП до 50% от полной скорости, сколько показывает загрузка ЦП? Возможно, в этот момент частота 50% снова становится знаменателем загрузки ЦП.

Формула расчета загрузки процессора:

RealTimeCPULoad=1-(RTCPUPerformance/CPUPerformanceBase)*100%.

Но как нельзя пить кашу палочками, так нельзя увлекаться ходом мыслей, не выпутавшись.

Идея 2: Контролируйте соотношение времени бега и сна

Если в пределах определенного временного диапазона, соотношение времени работы управляющей программы и времени ожидания также будет контролировать использование ЦП.

Способ мышления 2 осуществим и может быть реализован кодом за короткое время.

Например, если мы позволяем программе выполняться в течение 500 миллисекунд и спать в течение 500 миллисекунд за 1 секунду, можно считать, что загрузка ЦП составляет 50%.

Для реализации идеи 2 нам необходимо прояснить следующие вопросы:

  1. Каков статистический цикл загрузки ЦП? Есть ли функция или метод для получения количества циклов для ЦП?
  2. Как сделать процессор "занятым"?
  3. Как заставить ЦП «простаивать»?
  4. Правила статистики использования многоядерного процессора?
  5. Как выразить ось X синусоиды: время?

Статистический период загрузки процессора

Глядя на диспетчер задач, можно примерно сделать вывод, что статистический период составляет 1 секунду. На самом деле разные значения параметров нужно тестировать в программе.

держите процессор «занятым»

Согласно описанию «Красота программирования», когда программа выполняет операции, некоторые сложные операции и бесконечные циклы, скорость использования ЦП может увеличиваться. Какой способ следует использовать?

Согласно решению, в течение периода времени, когда ЦП занят, коэффициент использования ЦП должен быть 100% в течение короткого времени. Поэтому нам необходимо исследовать и протестировать, какой метод может довести коэффициент использования ЦП до 100%. Заинтересованные студенты могут проверить, отличаются ли следующие операции в более поздних программах: (1) Рассчитайте значение MD5 (2) Выполнить операцию +1 (3) Выполнить пустой цикл

Пусть процессор «простаивает» вниз

Подобно функции Sleep в языке C, в Go также есть функция time.Sleep(time.Duration) Параметр time.Duration представляет период времени для сна.

Правила статистики использования многоядерных ЦП

Если ЦП имеет два ядра, одно из которых загружено на 100 %, а другое ядро ​​бездействует, что произойдет с использованием ЦП?

Сначала выдвинули гипотезу: коэффициент занятости ЦП процессора задач Windows — это суммарный коэффициент занятости нескольких ядер, то есть формула коэффициента занятости ЦП из N ядер:

CPU占用率 = (Z_1 + Z_2 + ... + Z_N) / N

Среди них Z_i представляет коэффициент использования i-го ядра.

В последующих программах вы можете проверить, как достичь желаемой цели, настроив разное количество сопрограмм-горутин. Значения эталонной настройки: 1, 2 (количество ядер), 4 (количество логических процессоров).

Как выразить ось X: время

e61190ef76c6a7ef00b9298bf7faaf51f2de6684.jpg

image.png

Как показано на рисунке, на рисунке показаны синусоидальная кривая и окно использования ЦП.

Диапазон значений синусоидальной функции sin(X) находится в интервале [-1, 1], а интервал использования ЦП равен [0, 100%]. получить:

                        CPU利用率 = (sin(x) + 1) / 2, 其中x为程序运行时间

Диспетчер задач показывает, что окно времени использования ЦП составляет 60 секунд, и один цикл функции синуса находится в интервале [0, 2π], и выполняется отображение из [0, 60] -> [0, 2π]; то есть, когда время изменяется от 0 до 60 секунд, изменение x составляет 0 ~ 2π, то есть, установив размер шага x в секунду равным 2π/60 ≈ 0,1, 60-секундное окно может нарисовать полное синусоида. То есть, когда программа работает x секунд:

                      CPU利用率 = ( sin(0.1x) + 1 )/ 2,其中x为程序运行秒数

код реализации

Следующий код реализует синусоидальную функцию рендеринга загрузки ЦП:

package main

import (
	"fmt"
	"math"
	"time"
)

func main() {
    // 通过设置不同的coreNum测试多核心CPU利用率
	coreNum := 4
	for i := 0; i < coreNum; i++ {
		go task(i)
	}
    // 通过等待输入实现main-goroutine不会终止
	a := ""
	fmt.Scan(&a)

}

func task(id int) {
	var j float64 = 0.0
    // 通过设置step来决定一个60秒的统计窗口展示几个正弦函数周期
    var step float64 = 0.1
	for j = 0.0; j < 8*2*math.Pi; j += step {
		compute(1000.0, math.Sin(j)/2.0+0.5, id)
	}
}

/**
* t 一个总的CPU利用率的统计周期,1000毫秒,感兴趣的可以测试一下时间段小于1000毫秒与大于1000毫秒的情况下曲线如何
* percent [0, 1], CPU利用率百分比
*/
func compute(t, percent float64, id int) {
	// t 总时间,转换为纳秒
	var r int64 = 1000 * 1000
	totalNanoTime := t * (float64)(r)               // 纳秒
	runtime := totalNanoTime * percent              // 纳秒
	sleeptime := totalNanoTime - runtime            // 纳秒
	starttime := time.Now().UnixNano()              // 当前的纳秒数
	d := time.Duration(sleeptime) * time.Nanosecond // 休眠时间
	fmt.Println("id:", id, ", totaltime = ", t, ", runtime = ", runtime, ", sleeptime = ", sleeptime, " sleep-duration=", d, ", nano = ", time.Now().UnixNano())
	for float64(time.Now().UnixNano())-float64(starttime) < runtime {
		// 此处易出错:只能用UnixNano而不能使用Now().Unix()
		// 因为Unix()的单位是秒,而整个运行周期
	}
	time.Sleep(d)
}

проблема мышления

Вот несколько вопросов для размышления:

  1. computeЗачем конвертировать в наносекунды в функции?

A↑: Поскольку период составляет 1000 миллисекунд, что составляет 1 секунду, вы не можете выполнить цикл за секунды. Конечно, миллисекунды или микросекунды также можно использовать, но секунды использовать нельзя, и я нашел только две знакомые функции, time.Now().UnixNano(), time.Now().Unix(), так что я могу использовать только первая наносекунда, парни могут попробовать использовать вторую, чтобы ответить, что происходит

  1. Для нескольких логических процессоров после запуска в течение определенного периода времени ход выполнения каждой сопрограммы отличается.Почему это? Как сохранить синхронизацию?A↑: Прогресс отличается, 1 — на него могут влиять другие программы, 2 — скорость каждого ядра немного отличается. сквозьcomputeвместо передачи 1000 миллисекунд для достижения синхронизации или использовать другие методы синхронизации

  2. Что произойдет, если некоторые ядра всегда «простаивают», а некоторые ядра всегда «заняты»? В чем разница между выполнением различных операций в цикле?

Ответ ↑: Проверьте сами

  1. Можете ли вы устранить влияние других программ, занимающих процессор?

Ответ ↑:Я понятия не имею. Попробуйте получить загрузку процессора:github/shirou/gopsutil/cpu, и каждый раз, когда вы вводитеcomputeфункция проходит в исходном процентеpercentПроцент выполнения других программ был удален из программы, но позже выяснилось, что он был ограничен методом gopsutil/cpu для получения загрузки ЦП.cpu.Percent(duration time.Duration, percpu bool)Получение самого метода использования процессора занимает 1 секунду, поэтому вы получаете очень скачкообразную кривую. другого способа пока не нашел. Добро пожаловать друзья, которые знают, что это в комментариях, чтобы оставить сообщение для совета