c++打字机效果延迟问题?

问题描述 投票:0回答:1

我创建了这段代码来创建打字机控制台效果:

void fastType(const std::string& text, int delay)
{
    for (char c : text)
    {
        std::cout << c;
        std::this_thread::sleep_for(std::chrono::nanoseconds(delay));
    }
}

void fastType(const std::string& text, int delay = 2);

使用示例:

std::string message = "hello world...";

fastType(message);

在 Debug 模式下,该函数似乎有超过 10 毫秒的延迟,但是当我将其设置为 Release 模式时,它似乎有 10 毫秒左右的延迟,并且打印速度没有更快?我完全不知道为什么会发生这种情况。另外,我正在使用 Visual Studio 2022。

我尝试将其更改为

std::chrono::milliseconds(delay)
并将延迟设置为低于10毫秒,但它并没有变得更快。我尝试在
std::cout.flush();
行之前添加
std::this_thread::sleep_for(std::chrono::nanoseconds(delay));
,但它没有做任何事情(chatgpt 说要尝试一下)。我真的很困惑,不知道是什么导致了这个问题,所以任何有关如何使用打字机效果快速打印文本段落的提示将不胜感激!

注意:我实际上并没有尝试将延迟设置为 2 纳秒,而是尝试如何使延迟短于 16 毫秒以及为什么会发生这种情况。

c++ visual-studio console-application delay
1个回答
0
投票

这个问题其实涉及到操作系统的线程调度以及代码的一些底层原理。

由于与std::this_thread::sleep_for()函数相关的微软文档没有解释其底层实现,所以这里我将使用Sleep()方法:

void Sleep(
 [in] DWORD dwMilliseconds
);

这个方法在文档中有更详细的解释,所以我们可以弄清楚为什么delaytime不能小于16ms。

操作系统有一个用于调度任务的计时器,其分辨率通常在 10 到 15 毫秒之间。这就是系统时钟分辨率。 操作系统根据这个时钟周期来调度系统线程。如果你的线程的睡眠时间太短,比如0.01毫秒,那么,正如文档中提到的,实际的睡眠时间将小于设置的时间。但是,如果休眠时间在3ms或5ms左右,在相同精度内但小于系统时钟周期,则线程将等到下一个时钟周期执行。这就是为什么延迟时间并不总是像您预期的那样。

在官方文档中,针对这种情况,提供了timeBeginPeriod(5);、timeBeginPeriod()、timeEndPeriod()方法来调整系统时钟的精度。这两个方法中的变量必须一致,并且在定时器之前和之后立即使用。

我还写了一段关于测试线程延迟的代码供大家参考。在发布和调试模式下都可以设置小于16毫秒的延迟。当然,你也可以用你原来的方法,经过测试,也是有效的。 这里之所以使用Sleep()方法,是因为它的底层逻辑可以在官方文档中找到。相比之下,std::this_thread::sleep_for()的文档没有提供其逻辑的详细解释,因此我们只能推断其逻辑与Sleep()类似。

#include <windows.h>
#include <chrono>
#include <iostream>
#include <thread>
 
#include <timeapi.h>
#pragma comment(lib, "winmm.lib")
int main()
{
 
using namespace std::chrono_literals;
 
std::cout << "Hello waiter\n" << std::flush;
 
const auto start = std::chrono::high_resolution_clock::now();
 
timeBeginPeriod(10);
//std::this_thread::sleep_for(6ms) ;   // sleep_for() works too.
Sleep(6);
timeEndPeriod(10);
const auto end = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double, std::milli> elapsed = end - start;
 
std::cout << "Waited " << elapsed.count() << " ms\n";
}

如果您使用它,只需包含以下部分:

timeBeginPeriod(10);
//std::this_thread::sleep_for(6ms) ;   // sleep_for() works too.
Sleep(6);
timeEndPeriod(10);

其余用于监测睡眠时间。 希望我的回答能够对您有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.