记录测试中发现的sleep_for时间的微小差异,产生的性能的巨大差异
// PerfTest.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <thread>
#include <chrono>
//
// Thread pool timer callback function template
//
VOID
CALLBACK
MyTimerCallback(
PTP_CALLBACK_INSTANCE Instance,
PVOID Parameter,
PTP_TIMER Timer
)
{
// Instance, Parameter, and Timer not used in this example.
UNREFERENCED_PARAMETER(Instance);
UNREFERENCED_PARAMETER(Parameter);
UNREFERENCED_PARAMETER(Timer);
//
// Do something when the timer fires.
//
_tprintf(_T("MyTimerCallback: timer has fired.\n"));
}
//
// This is the thread pool work callback function.
//
VOID
CALLBACK
MyWorkCallback(
PTP_CALLBACK_INSTANCE Instance,
PVOID Parameter,
PTP_WORK Work
)
{
// Instance, Parameter, and Work not used in this example.
UNREFERENCED_PARAMETER(Instance);
UNREFERENCED_PARAMETER(Parameter);
UNREFERENCED_PARAMETER(Work);
BOOL bRet = FALSE;
thread_local int idx = 0;
idx++;
int sum = 0;
for (int i = 0; i < 1000000; i++)
{
sum += i;
}
//
// Do something when the work callback is invoked.
//
{
_tprintf(_T("MyWorkCallback: Task performed. sum: %d, idx: %d\n"), sum, idx);
}
return;
}
VOID
DemoCleanupPersistentWorkTimer()
{
BOOL bRet = FALSE;
PTP_WORK work = NULL;
PTP_TIMER timer = NULL;
PTP_POOL pool = NULL;
PTP_WORK_CALLBACK workcallback = MyWorkCallback;
PTP_TIMER_CALLBACK timercallback = MyTimerCallback;
TP_CALLBACK_ENVIRON CallBackEnviron;
PTP_CLEANUP_GROUP cleanupgroup = NULL;
FILETIME FileDueTime;
ULARGE_INTEGER ulDueTime;
UINT rollback = 0;
InitializeThreadpoolEnvironment(&CallBackEnviron);
//
// Create a custom, dedicated thread pool.
//
pool = CreateThreadpool(NULL);
if (NULL == pool) {
_tprintf(_T("CreateThreadpool failed. LastError: %u\n"),
GetLastError());
goto main_cleanup;
}
rollback = 1; // pool creation succeeded
//
// The thread pool is made persistent simply by setting
// both the minimum and maximum threads to 1.
//
SetThreadpoolThreadMaximum(pool, 5);
bRet = SetThreadpoolThreadMinimum(pool, 1);
if (FALSE == bRet) {
_tprintf(_T("SetThreadpoolThreadMinimum failed. LastError: %u\n"),
GetLastError());
goto main_cleanup;
}
//
// Create a cleanup group for this thread pool.
//
cleanupgroup = CreateThreadpoolCleanupGroup();
if (NULL == cleanupgroup) {
_tprintf(_T("CreateThreadpoolCleanupGroup failed. LastError: %u\n"),
GetLastError());
goto main_cleanup;
}
rollback = 2; // Cleanup group creation succeeded
//
// Associate the callback environment with our thread pool.
//
SetThreadpoolCallbackPool(&CallBackEnviron, pool);
//
// Associate the cleanup group with our thread pool.
// Objects created with the same callback environment
// as the cleanup group become members of the cleanup group.
//
SetThreadpoolCallbackCleanupGroup(&CallBackEnviron,
cleanupgroup,
NULL);
//
// Create work with the callback environment.
//
work = CreateThreadpoolWork(workcallback,
NULL,
&CallBackEnviron);
if (NULL == work) {
_tprintf(_T("CreateThreadpoolWork failed. LastError: %u\n"),
GetLastError());
goto main_cleanup;
}
rollback = 3; // Creation of work succeeded
for (int i = 0; i < 1000000000; i++)
{
//
// Submit the work to the pool. Because this was a pre-allocated
// work item (using CreateThreadpoolWork), it is guaranteed to execute.
//
SubmitThreadpoolWork(work);
std::this_thread::sleep_for(std::chrono::nanoseconds(100));
}
//
// Create a timer with the same callback environment.
//
timer = CreateThreadpoolTimer(timercallback,
NULL,
&CallBackEnviron);
if (NULL == timer) {
_tprintf(_T("CreateThreadpoolTimer failed. LastError: %u\n"),
GetLastError());
goto main_cleanup;
}
rollback = 4; // Timer creation succeeded
//
// Set the timer to fire in one second.
//
ulDueTime.QuadPart = (ULONGLONG)-(1 * 10 * 1000 * 1000);
FileDueTime.dwHighDateTime = ulDueTime.HighPart;
FileDueTime.dwLowDateTime = ulDueTime.LowPart;
SetThreadpoolTimer(timer,
&FileDueTime,
0,
0);
//
// Delay for the timer to be fired
//
Sleep(1500);
//
// Wait for all callbacks to finish.
// CloseThreadpoolCleanupGroupMembers also releases objects
// that are members of the cleanup group, so it is not necessary
// to call close functions on individual objects
// after calling CloseThreadpoolCleanupGroupMembers.
//
CloseThreadpoolCleanupGroupMembers(cleanupgroup,
FALSE,
NULL);
//
// Already cleaned up the work item with the
// CloseThreadpoolCleanupGroupMembers, so set rollback to 2.
//
rollback = 2;
goto main_cleanup;
main_cleanup:
//
// Clean up any individual pieces manually
// Notice the fall-through structure of the switch.
// Clean up in reverse order.
//
switch (rollback) {
case 4:
case 3:
// Clean up the cleanup group members.
CloseThreadpoolCleanupGroupMembers(cleanupgroup,
FALSE, NULL);
case 2:
// Clean up the cleanup group.
CloseThreadpoolCleanupGroup(cleanupgroup);
case 1:
// Clean up the pool.
CloseThreadpool(pool);
default:
break;
}
return;
}
int main(void)
{
DemoCleanupPersistentWorkTimer();
return 0;
}
上面是测试用的代码,我测试了如下两种情况:
(1)std::this_thread::sleep_for(std::chrono::nanoseconds(100));
(2)std::this_thread::sleep_for(std::chrono::nanoseconds(101));
测试使用的IDE是VS2022,如下图所示

测试的是release编译,使用Start Without Debugging启动。根据测试结果,使用100纳秒的sleep时间,CPU占用大约为14%到22%,而使用101纳秒的sleep时间,CPU占用为0%到4%,其中大多数时间显示为0%(表示低于1%)。暂时没有调查具体原因,先记录下来。如果您对这个原因有想法,欢迎指教。
浙公网安备 33010602011771号