如何估计线程上下文切换开销?

2024-03-20

我正在尝试通过实时截止日期来提高线程应用程序的性能。它运行在 Windows Mobile 上并用 C / C++ 编写。我怀疑高频率的线程切换可能会导致有形的开销,但既不能证明也不能反驳它。众所周知,缺乏证据并不是相反的证明:)。

因此我的问题是双重的:

  • 如果存在的话,我在哪里可以找到切换线程上下文成本的实际测量值?

  • 在不花时间编写测试应用程序的情况下,有哪些方法可以估计现有应用程序中的线程切换开销?

  • 有谁知道如何找出给定线程的上下文切换(开/关)数量?


我怀疑您是否可以在网络上的某个地方找到任何现有平台的这种开销。存在太多不同的平台。开销取决于两个因素:

  • CPU,因为必要的操作在不同的 CPU 类型上可能更容易或更难
  • 系统内核,因为不同的内核必须在每个交换机上执行不同的操作

其他因素包括转换如何发生。切换可以发生在以下情况:

  1. 该线程已使用其所有时间量。当一个线程启动时,它可能会运行一段给定的时间,然后必须将控制权返回给内核,内核将决定谁是下一个。

  2. 线程被抢占。当另一个线程需要 CPU 时间并且具有更高优先级时,就会发生这种情况。例如。处理鼠标/键盘输入的线程可能就是这样的线程。无论什么线程owns现在的CPU,当用户键入某些内容或单击某些内容时,他不想等到当前线程时间片完全用完,他希望看到系统立即做出反应。因此,有些系统会让当前线程立即停止,并将控制权返回给其他具有更高优先级的线程。

  3. 线程不再需要 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 也不算太糟糕。我猜如果没有这些东西,每秒可能的线程切换数量至少是两倍。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何估计线程上下文切换开销? 的相关文章

  • 如果 JSON.NET 中的值为 null 或空格,则防止序列化

    我有一个对象需要以这样的方式序列化 即 null 和 空白 空或只是空格 值都不会序列化 我不控制对象本身 因此无法设置属性 但我知道所有属性都是字符串 环境NullValueHandling显然 忽略 只能让我找到解决方案的一部分 它 似
  • 将设置函数(setter)标记为 constexpr 的目的是什么? [复制]

    这个问题在这里已经有答案了 我无法理解将 setter 函数标记为的目的constexpr 自 C 14 起这是允许的 我的误解来自以下情况 我使用 constexpr c tor 声明一个类 并且我将通过创建该类的 constexpr 实
  • 一段时间后终止线程的最 Pythonic 方法

    我想在线程中运行一个进程 它正在迭代一个大型数据库表 当线程运行时 我只想让程序等待 如果该线程花费的时间超过 30 秒 我想终止该线程并执行其他操作 通过终止线程 我的意思是我希望它停止活动并优雅地释放资源 我认为最好的方法是通过Thre
  • C# 处理标准输入

    我目前正在尝试通过命令行断开与网络文件夹的连接 并使用以下代码 System Diagnostics Process process2 new System Diagnostics Process System Diagnostics Pr
  • 如何以编程方式播放 16 位 pcm 数组 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有一个包含 16 位 pcm 值的短 数组 我希望能够在不添加任何标题 也不将任何文件保存到内存的情况下播放它 我知道我可能需要一个提供
  • 全局使用和 .NET Standard 2.0

    我最近意识到我可以使用 C 10 功能文件范围的命名空间在 NET Standard 2 0 项目中也可以通过设置
  • 带有运算符语法的错误消息,但不带有函数语法的错误消息

    为什么我在调用 unary 时收到错误消息 使用运算符语法 如果我用函数语法调用它就可以了 现场演示 https godbolt org z j7AbeQ template
  • 将日期时间转换为指定格式

    我有这个日期格式yy MM dd HH mm ss ex 12 02 21 10 56 09 问题是 当我尝试使用以下代码将其转换为不同格式时 CDate 12 02 21 10 56 09 ToString MMM dd yyyy HH
  • C# 编译器数字文字

    有谁知道 C 编译器数字文字修饰符的完整列表 默认情况下 声明 0 使其成为 Int32 声明 0 0 使其成为 Double 我可以在末尾使用文字修饰符 f 来确保某些内容被视为 Single 例如像这样 var x 0 x is Int
  • 静态类与类的实例

    我有一个静态类 用于访问我的公共属性 整个应用程序的全局属性 和我在应用程序运行期间使用的方法 例如 我在静态类中设置了一些属性 并且在应用程序运行时我可以从属性中获取值 但我可以使用单例模式创建非静态类并以相同的方式使用它 问题 对于我的
  • 如何在win32中使用GetSaveFileName保存文件?

    我编写此代码是为了获取 fileName 来保存我的文件 include stdafx h include
  • 子目录中的头文件(例如 gtk/gtk.h 与 gtk-2.0/gtk/gtk.h)

    我正在尝试使用 GTK 构建一个 hello world 其中包括以下行 include
  • Linq.Select() 中的嵌套表达式方法调用

    I use Select i gt new T 每次手动点击数据库后将我的实体对象转换为 DTO 对象 以下是一些示例实体和 DTOS 用户实体 public partial class User public int Id get set
  • printf或iostream如何指定点后的最大位数

    字符串采用什么格式printf or iomanip我应该使用 iostream 中的运算符以以下格式打印浮点数 125 0 gt 125 125 1 gt 125 1 125 12312 gt 125 12 1 12345 gt 1 12
  • 如果“嵌入式”SQL 2008 数据库文件不存在,如何创建它?

    我使用 C ADO Net 和在 Server Management Studio 中创建的嵌入式 MS SQL 2008 数据库文件 附加到 MS SQL 2008 Express 创建了一个数据库应用程序 有人可以向我指出一个资源 该资
  • 将 Swagger 与命名空间版本的 WebApi 结合使用

    我已经找到了如何使用基于名称空间的 WebAPI 版本这个班 https aspnet codeplex com SourceControl changeset view dd207952fa86 Samples WebApi Namesp
  • 将 char 绑定到枚举类型

    我有一段与此非常相似的代码 class someclass public enum Section START MID END vector section Full void ex for int i 0 i section
  • 如何在c linux中收听特定接口上的广播?

    我目前可以通过执行以下操作来收听我编写的简单广播服务器 仅广播 hello int fd socket PF INET SOCK DGRAM 0 struct sockaddr in addr memset addr 0 sizeof ad
  • 如何提高环复杂度?

    对于具有大量决策语句 包括 if while for 语句 的方法 循环复杂度会很高 那么我们该如何改进呢 我正在处理一个大项目 我应该减少 CC gt 10 的方法的 CC 并且有很多方法都存在这个问题 下面我将列出一些例如我遇到的问题的
  • 嵌入式二进制资源 - 如何枚举嵌入的图像文件?

    我按照中的说明进行操作这本书 http www apress com book view 9781430225492 关于资源等的章节 我不太明白的是 如何替换它 images Add new BitmapImage new Uri Ima

随机推荐