Я сомневаюсь, что вы можете найти эти накладные расходы где-то в сети для любой существующей платформы. Существует слишком много разных платформ. Накладные расходы зависят от двух факторов:
- ЦП, так как необходимые операции могут быть проще или сложнее на разных типах ЦП
- Системное ядро, так как разные ядра должны будут выполнять разные операции на каждом коммутаторе
Другие факторы включают в себя то, как происходит переключение. Переключение может иметь место, когда
поток использовал весь свой квант времени. Когда поток запускается, он может работать в течение заданного промежутка времени, прежде чем ему придется вернуть управление ядру, которое решит, кто следующий.
поток был прерван. Это происходит, когда другому потоку требуется процессорное время и он имеет более высокий приоритет. Например. поток, который обрабатывает ввод с клавиатуры / мыши, может быть таким потоком. Неважно, какой поток владеет процессором прямо сейчас, когда пользователь что-то печатает или щелкает что-то, он не хочет ждать, пока квант времени текущих потоков не будет полностью использован, он хочет видеть систему реагировать сразу. Таким образом, некоторые системы будут немедленно останавливать текущий поток и возвращать управление другому потоку с более высоким приоритетом.
потоку больше не требуется процессорное время, потому что он блокирует какую-то операцию или просто вызывает sleep () (или подобный), чтобы остановить работу.
Теоретически эти 3 сценария могут иметь различное время переключения потоков. Например. Я ожидаю, что последний будет самым медленным, так как вызов sleep () означает, что процессор возвращен ядру, и ядру необходимо настроить вызов пробуждения, который будет гарантировать, что поток проснется после количество времени, которое он запросил для сна, затем он должен вывести поток из процесса планирования, а после пробуждения потока он должен снова добавить поток в процесс планирования. Все эти крутые шаги займет некоторое время. Таким образом, фактический сон-вызов может быть дольше, чем время, необходимое для переключения на другой поток.
Я думаю, что если вы хотите знать наверняка, вы должны тестировать. Проблема в том, что вам обычно приходится либо усыплять потоки, либо синхронизировать их с помощью мьютексов. Спящая или блокирующая / разблокирующая мьютексы сама по себе накладные расходы. Это означает, что ваш тест будет включать и эти накладные расходы. Не имея мощного профилировщика, позже трудно сказать, сколько процессорного времени было использовано для фактического переключения и сколько для вызова сна / мьютекса. С другой стороны, в реальном сценарии ваши потоки будут либо спать, либо синхронизироваться через блокировки. Тест, который просто измеряет время переключения контекста, является синтетическим тестом, поскольку он не моделирует сценарий реальной жизни. Тесты намного более «реалистичны», если они основаны на реальных сценариях. Какой смысл использовать тест GPU, который говорит мне, что мой GPU теоретически может обрабатывать 2 миллиарда полигонов в секунду, если этот результат никогда не будет достигнут в реальном 3D приложении? Разве не было бы намного интереснее узнать, сколько полигонов в реальном 3D-приложении может обрабатывать графический процессор в секунду?
К сожалению, я ничего не знаю о программировании Windows. Я мог бы написать приложение для Windows на Java или, возможно, на C #, но C / C ++ в Windows заставляет меня плакать. Я могу предложить вам только исходный код для POSIX.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
uint32_t COUNTER;
pthread_mutex_t LOCK;
pthread_mutex_t START;
pthread_cond_t CONDITION;
void * threads (
void * unused
) {
// Wait till we may fire away
pthread_mutex_lock(&START);
pthread_mutex_unlock(&START);
pthread_mutex_lock(&LOCK);
// If I'm not the first thread, the other thread is already waiting on
// the condition, thus Ihave to wake it up first, otherwise we'll deadlock
if (COUNTER > 0) {
pthread_cond_signal(&CONDITION);
}
for (;;) {
COUNTER++;
pthread_cond_wait(&CONDITION, &LOCK);
// Always wake up the other thread before processing. The other
// thread will not be able to do anything as long as I don't go
// back to sleep first.
pthread_cond_signal(&CONDITION);
}
pthread_mutex_unlock(&LOCK); //To unlock
}
int64_t timeInMS ()
{
struct timeval t;
gettimeofday(&t, NULL);
return (
(int64_t)t.tv_sec * 1000 +
(int64_t)t.tv_usec / 1000
);
}
int main (
int argc,
char ** argv
) {
int64_t start;
pthread_t t1;
pthread_t t2;
int64_t myTime;
pthread_mutex_init(&LOCK, NULL);
pthread_mutex_init(&START, NULL);
pthread_cond_init(&CONDITION, NULL);
pthread_mutex_lock(&START);
COUNTER = 0;
pthread_create(&t1, NULL, threads, NULL);
pthread_create(&t2, NULL, threads, NULL);
pthread_detach(t1);
pthread_detach(t2);
// Get start time and fire away
myTime = timeInMS();
pthread_mutex_unlock(&START);
// Wait for about a second
sleep(1);
// Stop both threads
pthread_mutex_lock(&LOCK);
// Find out how much time has really passed. sleep won't guarantee me that
// I sleep exactly one second, I might sleep longer since even after being
// woken up, it can take some time before I gain back CPU time. Further
// some more time might have passed before I obtained the lock!
myTime = timeInMS() - myTime;
// Correct the number of thread switches accordingly
COUNTER = (uint32_t)(((uint64_t)COUNTER * 1000) / myTime);
printf("Number of thread switches in about one second was %u\n", COUNTER);
return 0;
}
выход
Number of thread switches in about one second was 108406
Более 100'000 - это не так уж и плохо, хотя у нас есть блокировки и условные ожидания. Я полагаю, что без всего этого было бы как минимум вдвое больше переключателей потоков в секунду.