我怀疑您是否可以在网络上的某个地方找到任何现有平台的这种开销。存在太多不同的平台。开销取决于两个因素:
- CPU,因为必要的操作在不同的 CPU 类型上可能更容易或更难
- 系统内核,因为不同的内核必须在每个交换机上执行不同的操作
其他因素包括转换如何发生。切换可以发生在以下情况:
该线程已使用其所有时间量。当一个线程启动时,它可能会运行一段给定的时间,然后必须将控制权返回给内核,内核将决定谁是下一个。
线程被抢占。当另一个线程需要 CPU 时间并且具有更高优先级时,就会发生这种情况。例如。处理鼠标/键盘输入的线程可能就是这样的线程。无论什么线程owns现在的CPU,当用户键入某些内容或单击某些内容时,他不想等到当前线程时间片完全用完,他希望看到系统立即做出反应。因此,有些系统会让当前线程立即停止,并将控制权返回给其他具有更高优先级的线程。
线程不再需要 CPU 时间,因为它在某些操作上阻塞,或者只是调用 sleep() (或类似的)来停止运行。
理论上这3种场景可能会有不同的线程切换时间。例如。我预计最后一个是最慢的,因为调用 sleep() 意味着 CPU 被交还给内核,并且内核需要设置一个唤醒调用,以确保线程在大约它请求休眠的时间量,然后它必须将该线程从调度进程中删除,一旦线程被唤醒,它必须再次将该线程添加到调度进程中。所有这些陡峭的过程都需要一些时间。因此,实际的睡眠调用可能比切换到另一个线程所需的时间更长。
我认为如果你想确切地知道,你必须进行基准测试。问题是您通常必须使线程进入睡眠状态,或者必须使用互斥锁来同步它们。睡眠或锁定/解锁互斥体本身就有开销。这意味着您的基准测试也将包括这些开销。如果没有强大的分析器,以后就很难说有多少 CPU 时间用于实际切换以及睡眠/互斥调用使用了多少时间。另一方面,在现实生活场景中,您的线程也将休眠或通过锁同步。纯粹测量上下文切换时间的基准是综合基准,因为它不模拟任何现实生活场景。如果基准基于现实生活场景,则更加“现实”。如果 GPU 基准测试告诉我理论上我的 GPU 每秒可以处理 20 亿个多边形,但如果在现实生活中的 3D 应用程序中永远无法实现这一结果,那么 GPU 基准测试有什么用呢?了解现实生活中的 3D 应用程序每秒可以让 GPU 处理多少个多边形不是更有趣吗?
不幸的是我对 Windows 编程一无所知。我可以用 Java 或 C# 编写 Windows 应用程序,但 Windows 上的 C/C++ 让我哭泣。我只能为您提供一些 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;
}
Output
Number of thread switches in about one second was 108406
即使我们有锁定和条件等待,超过 100'000 也不算太糟糕。我猜如果没有这些东西,每秒可能的线程切换数量至少是两倍。