C/C++中如何稳定地每隔5ms执行某个函数?

windows下c定时器使用 windows下c定时器使用需求解决参考 需求 由于程序使用阻塞方式计时,导致程序效率过低,使用定时器来进行计时,保证程序效率 解决 https://docs.microsoft.com/en-us/previous-versions//ms713423(v=vs.85)?redirectedfrom=MSDN MMRESULT timeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBA 阅读详情

链接:https://www.zhihu.com/question/536739862/answer/2524011929

1. windows上的多媒体定时器       

5ms级别的绝对的准确定时是不可能的,在允许一定偏差的情况下是可行的。但是,方法不能是Sleep或者C++库,而是Win32 API中已经不常用的多媒体定时器,就是timeBeginPeriod、timeSetEvent那套API。

        在多媒体定时器里面可以指定定时分辨率,最小1ms。当指定定时分辨率小于当前操作系统使用的硬件定时器周期的情况下,它会对硬件定时器重新编程,以实现所要求的定时分辨率。当然,同时也会调整操作系统内核里的参数,保持线程调度时间片长度等其他方面都不受影响。

        由于多媒体定时器事件是由独立硬件产生的,它基本上没有积累误差,并且,它是从中断响应例程里面经过简单处理就转入用户态进行回调,从中断发生到进入用户态回调函数入口的延迟很短,但是回调函数里的用户态代码可能会被更高优先级的线程抢占,所以即使回调函数很短很简单,它能否在下一个事件到来之前运行完成并没有绝对保证。另外要注意,多媒体定时器的回调函数里面只能执行极其有限的任务。

        这里澄清一下,多媒体定时器调整定时精度并不会影响Windows线程调度时间片的长度,这是两码事。比方说,假设原先硬件定时器的中断周期是15ms,中断一次系统就查看一下有没有其他线程等着切换上来。现在通过多媒体定时器api设定每毫秒产生一个事件,那么它会把硬件定时器重新编程,让它1ms发一个中断,操作系统会响应每个中断,会每毫秒去回调多媒体定时器的事件处理函数,但是,负责线程时间片的那部分代码会把中断累计15次,才认为当前线程的时间片已用完,进行线程调度。

2. linux上的sleep测试

        非硬实时系统的确无法做到绝对精准可靠的定时。然而工程实践上,不要忽视操作系统和编译器这么多年的努力。有人手撸的线程池手撸过定时器,亲测核心数*100个定时器,20ms间隔,用单线程sleep计算超时然后分发给线程池执行回调,在回调中计算误差,不超过2%(实际为1.6%),而且NUMA环境依然运行稳定。所以至少在Linux上,只要系统负载不是过高,sleep定时基本可靠。

        使用的C++和标准库测试定时器:

static const constexpr auto kInterval = 5ms;
static const constexpr auto kDuration = 1min;
auto now = std::chrono::high_resolution_clock::now();
auto tick = now;
auto final = now + kDuration;
while (now < final) {
  tick += kInterval;
  std::this_thread::sleep_until(tick);
}

        不但用了sleep陷入上下文切换,还用的是标准库的API,而非系统API,猜猜看表现如何?

        用最笨的CMake Release编译,不加什么-march=native之类的歪门邪道,然后用户态执行,也不玩啥绑定核心、设置优先级和实时调度等等。

        误差计算方式为,每个tick对齐时间后,计算当前时刻和这个tick理论时刻的差值,将其追加到数组里,跑完完整时长后再统计和打印,避免打印输出造成干扰。

        测试系统环境分别为:

  • 系统:WSL2 Archlinux,内核:5.10.102.1-microsoft-standard-WSL2;
  • 系统:Windows 11 专业版 22H2,内核:25145.1000;
  • 系统:Ubuntu 18.04.5 LTS,内核:4.15.0-180-generic;
  • 系统:Ubuntu 18.04.5 LTS,内核:4.14.193-rt92-tegra premmpt-rt
CPU系统总负载操作系统编译器标准差(us)最大误差(us)95%误差(us)99%误差(us)
i9-9900k45%WSL2 Archlinuxgcc 11.2.011.648986.400208.000253.600
i9-9900k45%WSL2 Archlinuxclang 13.0.111.4081421.300177.600237.300
i9-9900k45%Windows 11 22H2MSVC 20197228.23016648.70014278.50015335.900
i9-9900k45%Windows 11 22H2clang 14.0.08871.74916475.50014771.20015519.200
Xeon 5217x25%Ubuntu 18.04 LTSgcc 7.5.057.60973.10658.51259.794
ARMv80.5%Ubuntu 18.04 premmpt-rtgcc 7.5.089.910128.74797.195101.769

        Windows+MSVC比较拉跨,时间轴全程都是乱的,因为Windows上默认时间片是15.625ms;而另一个回答中说到的游戏服务器代码,通过timeBeginPeriod设置时间片为1ms,至少在我的Win11专业版上是无效的,设置后通过GetSystemTimeAdjustment返回的时间片依然是15.625ms,可能得使用Windows Server才行;

        不过最神奇的是,WSL2的表现还挺不错,虽然这玩意本质上是个hyper-v虚拟机……99%误差在5%范围,这个精度基本可用;

        Linux表现非常优秀,误差全程保持在1.2%以内,这个精度完全可用;

        Linux的preempt-rt软实时内核表现反而更差,不知道是不是因为arm性能低一点,但是sleep也不吃性能啊。

然后,假如我们给每个tick增加100us的自旋呢?也就是sleep 4900us,然后自旋直到到超时?

static const constexpr auto kInterval = 5ms;
static const constexpr auto kSpin = 100us;
static const constexpr auto kDuration = 1min;
auto now = std::chrono::high_resolution_clock::now();
auto tick = now;
auto final = now + kDuration;
while (now < final) {
  tick += kInterval;
  std::this_thread::sleep_until(tick - kSpin);
  while (now < tick) {
    std::this_thread::yield();
    now = std::chrono::high_resolution_clock::now();
  }
}

作者:诸葛不亮
链接:https://www.zhihu.com/question/536739862/answer/2543502653
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

这里有个问题,就是yield有可能触发线程挂起,导致上下文切换。但是注释掉该行后,Linux和Windows的运行结果并未有显著变化,包括后面补充的timeBeginPeriod版本也是如此。

CPU系统总负载操作系统编译器标准差(us)最大误差(us)95%误差(us)99%误差(us)
i9-9900k45%WSL2 Archlinuxgcc 11.2.048.701570.70096.300151.500
i9-9900k45%WSL2 Archlinuxclang 13.0.150.495576.400106.000154.600
i9-9900k45%Windows 11 22H2MSVC 20198859.80918281.70014557.60015351.600
i9-9900k45%Windows 11 22H2clang 14.0.08933.11116552.80014747.90015478.800
Xeon 5217x25%Ubuntu 18.04 LTSgcc 7.5.00.36218.4270.5580.690
ARMv88%Ubuntu 18.04 premmpt-rtgcc 7.5.00.73814.9160.8150.893

        很神奇吧,Linux上的误差直线下降到万分之一,约等于没有误差了。

        Windows上受限于15.625ms的时间片,还是无法保证精度。

        WSL2上平均误差略有提升,但误差波动和最大误差显著下降,整体运行更加平稳,99%场景下保持3%误差以内,如果能接受1%的偶发波动,那么也算完全可用。

完整代码如下:

#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <thread>
#include <vector>

using namespace std::literals::chrono_literals;

static const constexpr auto kInterval = 5ms;
static const constexpr auto kSpin = 100us;

int main(int argc, char* argv[]) {
  std::chrono::nanoseconds duration = 1min;
  if (argc > 1) {
    duration = std::chrono::seconds(std::atoi(argv[1]));
  }
  int ticks = duration / kInterval;
  std::vector<double> errors;
  errors.reserve(ticks);

  int digits = 0;
  do {
    ticks /= 10;
    ++digits;
  } while (ticks > 0);

  auto now = std::chrono::high_resolution_clock::now();
  auto begin = now;
  auto prev = now;
  auto tick = now;
  auto final = now + duration + kInterval;
  begin += kInterval;  // 多执行一次作为预热
  int i = 0;
  while (now < final) {
    prev = now;
    tick += kInterval;
    std::this_thread::sleep_until(tick - kSpin);
    now = std::chrono::high_resolution_clock::now();
    while (now < tick) {
      std::this_thread::yield();
      now = std::chrono::high_resolution_clock::now();
    }
    auto error =
        std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(
            now - tick);
    errors.push_back(error.count());
    ++i;
  }
  errors.erase(errors.begin());  // 统计时丢弃第一个预热tick

  std::ios::sync_with_stdio(false);
  std::cout.tie(nullptr);
  std::cout.precision(3);
  std::cout.setf(std::ios::fixed);
  double std_err = 0.0;
  double max_err = 0.0;
  for (size_t i = 0; i < errors.size(); ++i) {
    std_err += std::pow(errors.at(i), 2);
    max_err = std::max(std::abs(max_err), std::abs(errors.at(i)));
    std::cout << "tick " << std::setw(digits) << (i + 1)
              << " error: " << std::setw(8) << errors.at(i) << "us"
              << std::endl;
  }
  std_err = std::sqrt(std_err / errors.size());
  for (double& error : errors) {
    error = std::abs(error);
  }
  std::sort(errors.begin(), errors.end());
  double most_95 = errors.at(errors.size() * 0.95);
  double most_99 = errors.at(errors.size() * 0.99);
  auto elapsed =
      std::chrono::duration_cast<std::chrono::duration<double>>(now - begin);
  std::cout << "total " << errors.size() << " ticks in " << elapsed.count()
            << "s" << std::endl;
  std::cout << "std error: " << std_err << "us" << std::endl;
  std::cout << "max error: " << max_err << "us" << std::endl;
  std::cout << "95% error: " << most_95 << "us" << std::endl;
  std::cout << "99% error: " << most_99 << "us" << std::endl;

  return 0;
}

         查了一下MSDN,通过timeBeginPeriod设置时间片至1ms后,使用timeSetEvent建立系统级定时器,成功获得了比较理想的性能,大部分的tick误差降低到1ms以内。

(所以GetSystemTimeAdjustment依旧返回156250是在搞我是吧?)

        但是奇怪的是,在大约2000-10500tick范围内,时间间隔又回到了15.625ms,只有在大约首尾10s的范围内是正常的。

        使用sleep版本,在设置timeBeginPeriod后也差不多,只能稳定运行大约10s,统计结果基本一致。

        由于运行过于不稳定,所以修改了误差方式,改成计算两个tick之间的时间差,再减去5ms间隔,运行十秒的统计结果为:

total 2000 ticks in 9.999s
std error: 436.408us
max error: 1361.100us
95% error: 855.100us
99% error: 960.000us

        平均误差在10%左右,而且至少没丢tick,成功在刚好10s的时候触发了2000次,所以勉强能用吧…

20230303更新

手撸的简易版线程池和定时器优化过几轮,最近抽空跑了下benchmark,更新下数据。

定时器的调度还是开头的第一个方案,直接sleep到最近的一个tick,然后分发给线程池。实测只要不是系统里有乱七八糟的东西抢cpu,5msz何种精度根本不需要上硬实时。

1. Desktop

  • CPU: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz 8C16T
  • System: Arch Linux
  • Kernel-release: Linux 6.1.12-zen1-1-zen
  • Kernel-version: #1 ZEN SMP PREEMPT_DYNAMIC Tue, 14 Feb 2023 22:08:11 +0000
timersintervalticksstandard error
Single Shot
1620ms10.064172%
16020ms10.048121%
160020ms10.052030%
---------------------------------
Sync Single Shot
3220ms10.015647%
32020ms10.018143%
320020ms10.019471%
---------------------------------
Normal Timer
1620ms1000.094364%
16020ms1000.049935%
160020ms1000.047018%
---------------------------------
Sync Normal Timer
1620ms1000.009787%
16020ms1000.024087%
160020ms1000.037850%
---------------------------------
Light Timer
1620ms1000.079792%
16020ms1000.047847%
160020ms1000.066415%
---------------------------------
Sync Light Timer
1620ms1000.046064%
16020ms1000.018828%
160020ms1000.018925%

2. Desktop with NUMA

  • CPU: Intel(R) Xeon(R) Gold 5217 CPU @ 3.00GHz 8C16Tx2
  • System: Ubuntu 18.04.5 LTS
  • Kernel-release: Linux 4.15.0-201-generic
  • Kernel-version: #212-Ubuntu SMP Mon Nov 28 11:29:59 UTC 2022
timersintervalticksstandard error
Single Shot
3220ms10.083189%
32020ms10.068409%
320020ms10.065791%
---------------------------------
Sync Single Shot
3220ms10.013066%
32020ms10.013754%
320020ms10.018617%
---------------------------------
Normal Timer
3220ms1000.011256%
32020ms1000.027207%
320020ms1000.822226%
---------------------------------
Sync Normal Timer
3220ms1000.008387%
32020ms1000.089677%
320020ms1000.050699%
---------------------------------
Light Timer
3220ms1000.013912%
32020ms1000.012924%
320020ms1000.066572%
---------------------------------
Sync Light Timer
3220ms1000.008739%
32020ms1000.009238%
320020ms1000.094552%

3. Embbed Industrial PC

  • CPU: ARMv8 Processor rev 0 (v8l) 7C7T
  • System: Ubuntu 18.04.5 LTS
  • Kernel-release: Linux 4.14.193-rt92-tegra
  • Kernel-version: #1 SMP PREEMPT RT Mon Apr 19 02:11:35 PDT 2021
timersintervalticksstandard error
Single Shot
720ms10.070154%
7020ms10.136009%
70020ms10.248653%
---------------------------------
Sync Single Shot
720ms10.071237%
7020ms10.068406%
70020ms10.087798%
---------------------------------
Normal Timer
720ms1000.077910%
7020ms1000.078375%
70020ms1000.082158%
---------------------------------
Sync Normal Timer
720ms1000.086753%
7020ms1000.078405%
70020ms1000.087344%
---------------------------------
Light Timer
720ms1000.070703%
7020ms1000.064910%
70020ms1000.084942%
---------------------------------
Sync Light Timer
720ms1000.086785%
7020ms1000.060398%
70020ms1000.085978%

Light Timer是轻量级定时器,类似QObject::startTimer,只有一个id,没有timer对象管理。

Sync Timer是同步执行机制,回调函数直接在调度线程里就地执行,而不是分发到线程池。

3. 一种游戏编程方案

        提供一个游戏编程中的方案,大概的代码(windows下,如果需要改为其他系统需要替换对应的time_begin_period或者sleep函数):

time_begin_period(1); // windows中winmm.dll的timeBeginPeriod的封装

while(true) {
    auto start_ticks = get_current_ticks(); //执行前时间

    execute(); // 目标函数
    
    auto end_ticks = get_current_ticks(); //执行后时间
    auto cost_ticks = end_ticks - start_ticks; //执行当前帧花费的时间
    auto wait_ticks = milliseconds_to_ticks(5) - cost_ticks; //计算需要等待的时间
    if(wait_ticks <= 0) {
        continue; // 当前帧正好或者超时了,直接执行下一帧
    }
    if(wait_ticks > milliseconds_to_ticks(1)) {
        sleep(ticks_to_milliseconds(wait_ticks) - 1); // 如果等待时间大于1ms,就sleep
    }
    auto next_ticks = start_ticks + milliseconds_to_ticks(5); //下一次执行期望时间
    while (get_current_ticks() < next_ticks) {
        //空,原地等待
    }
}

虽然会牺牲少量的性能,但是可以在低负载情况下保证基本稳定在200帧。

        不过少数时候会出现 DeltaTime:5.1178 ms,甚至 DeltaTime:6.221 ms。当然可以通过减少sleep的时间来牺牲性能换去稍微稳定的精度。

Windows多媒体定时器(精确到1ms) MFC使用多媒体定时器,Windows多媒体定时器,多媒体定时器封装 阅读详情

相关推荐

whisper.cpp嵌入式部署指南:C/C++版Whisper离线语音识别实战

语音识别(ASR)是边缘智能的关键能力,而Whisper作为主流开源模型,其Python实现受限于内存、启动延迟与依赖复杂度,难以落地资源受限的嵌入式设备。whisper.cpp通过C/C++重写、静态图展开、INT16量化与零拷贝音频流水线,在不牺牲精度前提下实现毫秒级推理、确定性内存占用与纯离线运行。它支持ARM/RISC-V/x86等多架构,适配树莓派、ESP32、i.MX8M Mini等典型硬件,广泛应用于语音唤醒、工业语音日志、车载离线交互等场景。本文聚焦whisper.cpp的核心原理、量化策略

weixin_34060299的博客 536

进程让他每隔5秒钟执行一次(非阻塞)

在Linux实现一个定时器,不像Win32下那样直观。在Win32调用SetTimer就行了,在Linux下则没有相应函数可以直接调用。定时器作为一个常用的功能,在Linux当然也有相应实现。下面我们看看几种常用的方法。     要实现定时器功能,最土的办法实现莫过于用sleep/usleep来实现了。当然,它会阻塞当前线程,除了处理定时功能外,什么活也干不了。当然要解决这个问题不难,创建一个

非淡泊无以明志,非宁静无以致远 5059

Whisper.cpp:C/C++轻量化语音识别与离线部署实战指南

语音识别是边缘智能与嵌入式AI的关键能力,其核心挑战在于如何在资源受限设备上实现低延迟、低内存、高可用的本地化推理。Whisper.cpp 通过纯C/C++重写、GGML张量引擎、IQ4_XS整数量化等关键技术,将OpenAI Whisper大模型压缩为静态可执行文件,彻底摆脱Python、GPU和网络依赖。它代表了一种‘可预测性优先’的工程范式,在树莓派、工业控制器、车载ECU等场景中实现稳定RTF>1的实时识别。本文深入解析其轻量化推理原理、模型量化策略与C API集成方法,覆盖从编译避坑、音频预处理到

weixin_29952383的博客 350

C# While间隔5秒循环

使用while想达到间隔 5秒循环调用可以使用如下方法,就会间隔5秒调用方法。

寒冰的暖 1601

llama.cpp CPU推理实战:C/C++轻量化部署GGUF大模型

大语言模型推理不再依赖GPU和Python生态,CPU端原生推理正成为边缘计算与终端AI的关键路径。其核心在于将模型压缩、内存映射与硬件指令级优化深度耦合——GGUF格式实现零拷贝内存加载,C/C++提供确定性低延迟执行,量化策略(如Q4_K_M、Q5_K_M)平衡精度与吞吐,而CMake则作为跨平台硬件特性的编译时开关矩阵。这种技术组合显著降低部署门槛,支持在MacBook Air、树莓派、NAS甚至无显卡Windows设备上本地运行3B~7B级模型,广泛应用于私有知识库、离线助手、嵌入式AI交互等场景。

weixin_34353714的博客 359

Whisper.cpp深度解析:C/C++离线语音识别引擎原理与工程实践

语音识别作为人机交互核心能力,其边缘部署长期受限于Python生态的启动开销、内存不可控和依赖复杂等问题。Whisper.cpp通过纯C/C++重实现推理流水线,结合ggml张量库与混合量化技术,实现了低延迟、确定性内存占用和跨平台离线运行。它不依赖Python或GPU,支持ARM/RISC-V等嵌入式架构,适用于智能硬件、车载语音、会议记录等对实时性与可靠性要求严苛的场景。本文围绕C/C++实现、离线运行、嵌入式友好三大关键词,系统剖析其设计哲学、编译调优、流式处理及量产级稳定性保障机制。

weixin_33871366的博客 339

5个高效配置让Dev-CPP成为C/C++编程入门利器

Dev-CPP是一款轻量级C/C++集成开发环境,通过优化的代码编辑界面、智能补全功能和便捷的项目管理系统,为编程学习者和初级开发者提供了高效的开发体验。该工具在经典Dev-C++基础上进行了深度重构,保留了轻量特性的同时增强了现代化开发功能,特别适合C/C++初学者快速掌握编程基础。 ## 一、基础配置篇:从零开始搭建开发环境 ### 编译器安装与验证 **问题现象**:首次启动程序时出现

gitblog_00692的博客 331

Windows下VSCode配置C/C++代码跳转:从原理到实战

代码跳转是现代集成开发环境(IDE)和高级文本编辑器的核心功能,它基于语言服务器协议(LSP)实现,通过分析项目源代码、理解语法和语义,构建符号索引数据库。这项技术的核心价值在于极大提升了开发者在大型项目中的代码导航、理解和重构效率,尤其适用于C/C++这类需要复杂编译和链接过程的系统级编程。在实际工程实践中,配置一个稳定准确的代码跳转环境,是提升C/C++开发生产力的关键步骤。本文以Windows平台上的Visual Studio Code(VSCode)为例,深入解析如何通过配置编译器路径、包含目录和I

weixin_33860553的博客 448

VSCode中C/C++代码补全配置指南

对比C/C++ Extension与clangd在VSCode中的代码补全表现,详解如何通过c_cpp_properties.或Compilation Database实现高效索引。前者上手简单,后者精度更高,适合可编译项目的深度开发,兼顾体验与性能。

weixin_32673065的博客 1335

VSCode + MinGW-w64 配置 C/C++ 编译调试环境

在软件开发中,编辑器、编译器与调试器构成了最基础的工具链条。理解它们各自的功能与协作方式,是高效编程的起点。编辑器负责编写代码,编译器将源代码转换成可执行文件,调试器则用于排查程序运行中的错误。基于这一原理,使用轻量级工具构建定制化开发环境,已成为许多开发者的优先选择。例如,在 Windows 平台,通过 VSCode 集成 MinGW-w64 中的 GCC 编译器与 GDB 调试器,可以实现从代码编辑、语法提示、编译运行到断点调试的完整流程。这套方案完全免费开源,配置透明、易于迁移,特别适合 C/C++

weixin_33938733的博客 407

VSCode配置Keil插件解决C/C++头文件红色波浪线错误指南

在嵌入式开发中,集成开发环境(IDE)的智能感知功能对于提升编码效率至关重要。其工作原理依赖于语言服务器对代码的静态分析,通过解析包含路径和预定义宏来定位头文件与符号定义。当配置不当时,就会出现头文件找不到的红色波浪线错误,严重影响代码补全和跳转体验。这一问题的技术价值在于打通不同工具链的配置壁垒,实现编辑环境与编译环境的一致。在嵌入式开发场景,尤其是使用Keil MDK配合VSCode编辑器时,开发者常因路径配置缺失或错误而遇到此问题。本文聚焦于如何通过正确配置VSCode的c_cpp_propertie

weixin_30381317的博客 539

Visual Studio Code 高效开发 C/C++ 插件推荐

Visual Studio Code 高效开发 C/C++ 插件推荐

世界那么大,我想去看看~【随心更新,看世界去了😄】 2万+

Windows下使用MinGW-w64与VSCode搭建轻量高效的C/C++开发环境

在C/C++开发中,编译器工具链和集成开发环境是构建软件的基础。GCC作为跨平台的开源编译器,其原理是通过预处理、编译、汇编、链接等阶段将源代码转换为可执行文件。MinGW-w64作为GCC在Windows的移植版本,其技术价值在于提供了原生Windows支持,无需模拟层,可直接生成.exe文件,保证了与Linux/macOS开发体验的一致性。结合VSCode的轻量编辑器特性与丰富插件生态,这一组合特别适合快速原型开发、学习算法和跨平台项目。通过配置环境变量、tasks.json和launch.json,开

weixin_34357436的博客 502

c/c++计时

前言 学习需要。 1 秒(s) = 1000毫秒(ms)=1000000微妙(us) 1. 毫秒(ms)级计时 #include<time.h> // 所需要的头文件 double duration // 程序运行时间 time_t start = clock(); // 计时开始 ... // 所需要记录的时间的程序 time_t end = clock(); // 结束计时 du...

胡侃有料的博客 2134

C语言实现定时器(附完整源码)

C语言实现定时器(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 2070

VSCode配置C/C++开发环境完整指南

C/C++开发环境本质是编译器、调试器与智能感知的协同系统。其核心原理在于外部工具链(如GCC/Clang/MSVC)与编辑器配置文件(c_cpp_properties.json、tasks.json、launch.json)之间的精准映射。技术价值体现在消除头文件标红、实现Ctrl+Click跳转、支持F5断点调试等关键工程能力。典型应用场景包括算法刷题、嵌入式裸机开发、跨平台项目构建,尤其适合从Dev-C++或Code::Blocks迁移、拒绝Visual Studio重型方案的实战开发者。本文聚焦VS

weixin_28839629的博客 296

Whisper.cpp深度解析:C/C++实现的轻量级离线语音识别方案

语音识别是边缘智能的关键能力,其核心在于模型推理的轻量化、确定性与硬件适配性。Whisper.cpp通过C99纯实现、GGML张量格式与多级量化(如Q5_K),将OpenAI Whisper压缩至数十MB内存占用,摆脱Python依赖与GPU绑定,实现真正嵌入式部署。它不仅支持ARM/x86多架构编译,还提供音频预处理全链路C实现(stb_wave+kiss_fft)、线程安全推理API及低延迟流式扩展能力。本文聚焦Whisper.cpp的技术原理、量化权衡、跨平台编译实践与工业级集成方法,覆盖树莓派、Je

weixin_34318272的博客 486

手把手教你用USBasp给Arduino UNO烧写程序(ICSP模式,含BootLoader选择指南)

本文详细介绍了如何使用USBasp编程器通过ICSP模式为Arduino UNO烧写程序,包括硬件连接、软件配置、Hex文件处理和BootLoader选择指南。内容涵盖从新手入门到高级优化的全流程,帮助开发者高效完成烧写任务,特别适合需要修复BootLoader或进行量产烧写的用户。

weixin_33958381的博客 363

VSCode配置Qwen2.5-VL开发环境:C/C++扩展实战

本文介绍了如何在星图GPU平台上自动化部署基于 Qwen2.5-VL 的视觉定位chord视觉定位模型镜像,实现高效、低延迟的多模态视觉理解与目标定位。该镜像特别适用于智能摄像头中的实时物体检测与坐标标注、工业质检图像分析等边缘视觉定位场景,显著提升C/C++环境下的模型集成效率。

weixin_34438187的博客 489

单细胞专题(1) | 单细胞转录组研究样本准备指南(上)

单细胞RNA测序(scRNA-seq)是目前最前沿,能进行大规模实验的转录组研究技术,为理解细胞组成和动态生物学过程提供了很多新的见解。单细胞研究已经为我们理解发育过程,老化和疾病(如癌症)等提供了大量数据。在这里,小编主要就前期的样本准备与保存需注意问题给大家进行讲解,以备大家在不同的研究场景和研究背景下,走好单细胞转录组学研究的第一步。

bioyigene的博客 4227

SpotBugs使用

spotbugs命令行参数解析

javajingling的专栏 2946
上一篇: 【Linux驱动】内核模块编译 —— make modules 的使用(单模块编译、多模块编译)
下一篇: Makefile中诸多等号“:=, =, ?=和+=”的区别
土豆西瓜大芝麻
博客等级 码龄18年 1189粉丝 238原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值