Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C SetPixel随时间变慢_C_Winapi_Time_Pixels - Fatal编程技术网

C SetPixel随时间变慢

C SetPixel随时间变慢,c,winapi,time,pixels,C,Winapi,Time,Pixels,我喜欢在桌面窗口上设置像素,但有时它的行为会很奇怪 for(i=0;i<10000;i++) SetPixel(DC,100+100*sin((float)i/100),100+100*cos((float)i/100),0); 上面的代码应该打印10000像素,在屏幕的左上角画一个圆圈。但是如果我使用它很多次,它会变得越来越慢。下面的代码应提供这方面的示例: #include<windows.h> int main(){ Sleep(4000);//wait

我喜欢在桌面窗口上设置像素,但有时它的行为会很奇怪

for(i=0;i<10000;i++)
    SetPixel(DC,100+100*sin((float)i/100),100+100*cos((float)i/100),0);
上面的代码应该打印10000像素,在屏幕的左上角画一个圆圈。但是如果我使用它很多次,它会变得越来越慢。下面的代码应提供这方面的示例:

#include<windows.h>
int main(){
    Sleep(4000);//waiting you to be ready
    int i,j,k,l;
    HDC DC=GetDC(GetDesktopWindow());
    j=GetTickCount();//base time
    for(l=0;l<10;l++)
    {
        for(i=0;i<10000;i++)
            SetPixel(DC,rand()%1000,rand()%1000,0);//print 10000 random x,y pixel
        printf("%d\n",(k=GetTickCount())-j);//time duration from the last count
        for(i=0;i<10000;i++)
            SetPixel(DC,rand()%1000,rand()%1000,0);
        printf("%d\n",(j=GetTickCount())-k);
    }
    return 0;
}

为什么这个操作会随着时间的推移而变慢?

首先,清理一下测试代码:

#include<windows.h>

// number of pixels written in each run
#define NUM_PIXELS 50000

// range of pixel coordinates
#define MIN_RANGE 100
#define MAX_RANGE 1000
#define RANGE_MULT 10

// pause after each run to allow DWM to do its things
#define DWM_PAUSE 20 // seconds

HDC DC;

void bench(int range, int pause)
{
    int i, start;

    // let DWM digest previous pixels
    Sleep(pause*1000);

    // feed more pixels into the system
    start = GetTickCount();
    for (i = 0; i != NUM_PIXELS; i++)
    {
        SetPixel(DC, rand()%range, rand()%range, 0);
    }
    printf ("pause %d range %d duration %d\n", pause, range, GetTickCount()-start);
}

int main (void)
{
    DC=GetDC(GetDesktopWindow());

    int range;
    for (range = MIN_RANGE; range <= MAX_RANGE; range *= RANGE_MULT) bench(range, 0);
    for (range = MAX_RANGE; range >= MIN_RANGE; range /= RANGE_MULT) bench(range, 0);
    for (range = MIN_RANGE; range <= MAX_RANGE; range *= RANGE_MULT) bench(range, DWM_PAUSE);
    for (range = MAX_RANGE; range >= MIN_RANGE; range /= RANGE_MULT) bench(range, DWM_PAUSE);
    return 0;
}
在禁用Aero的情况下运行相同的程序:

c:\Dev\PHP\_StackOverflow\C++\SlowSetPixel\Release>SlowSetPixel.exe
pause 0 range 100 duration 47
pause 0 range 1000 duration 31
pause 0 range 1000 duration 31
pause 0 range 100 duration 31
pause 20 range 100 duration 63
pause 20 range 1000 duration 47
pause 20 range 1000 duration 47
pause 20 range 100 duration 62
有人偷了我的CPU吗? 是的,我当场抓住了罪犯

这些测试最好在任务管理器打开时使用,以便在任务管理器工作时观察可怕的dwm.exe桌面窗口

在第一次执行过程中,dwm.exe被卡在100%的CPU上,使用我电脑的4个核心之一,其内存消耗上升到了荒谬的程度,从大约28 Mb增加到112 Mb

即使暂停20秒,血腥的DWM甚至还没有消化完像素。这就是为什么测试的第二部分显示了稍长的执行时间

如果没有Aero,SetPixel函数基本上不起任何作用。DC不是无效的,但SetPixel不执行任何可见修改

搞什么鬼? 之所以会发生这种情况,可能是因为有了炫目的全新自Vista桌面界面,最终桌面位图的合成是通过这个dwm.exe进程完成的。每个窗口都有自己的图形缓冲区,dwm.exe会收到任何更改的通知,并重新计算背景中每个像素的最终外观

将像素直接写入桌面窗口基本上破坏了这个小方案,因为一个外部程序访问了dwm.exe的私有游乐场

我不知道微软的人是如何处理这个案子的,但很明显他们并没有以一种有效的方式来处理。 看起来桌面的多个副本被加载到内存中,可能是为了允许一个副本被修改,而其他副本则集成在合成链中

dwm.exe占用的内存量大约是1000*1000 RGBA位图大小的25倍。 测试表明,该量随改性区域的表面而变化

我怀疑这个愚蠢的过程每秒对屏幕进行20或30次采样,并在看到诸如SetPixel调用之类的奇怪情况时创建屏幕修改部分的新副本

这么糟糕的结果,我想知道为什么他们一开始就允许访问桌面DC,只允许人们用10行代码涂抹屏幕


高效的屏幕访问现在需要使用DirectX来绕过糟糕的向后兼容性层,您必须通过它来使用过时的Win32 GDI操作位图。

首先,清理一下测试代码:

#include<windows.h>

// number of pixels written in each run
#define NUM_PIXELS 50000

// range of pixel coordinates
#define MIN_RANGE 100
#define MAX_RANGE 1000
#define RANGE_MULT 10

// pause after each run to allow DWM to do its things
#define DWM_PAUSE 20 // seconds

HDC DC;

void bench(int range, int pause)
{
    int i, start;

    // let DWM digest previous pixels
    Sleep(pause*1000);

    // feed more pixels into the system
    start = GetTickCount();
    for (i = 0; i != NUM_PIXELS; i++)
    {
        SetPixel(DC, rand()%range, rand()%range, 0);
    }
    printf ("pause %d range %d duration %d\n", pause, range, GetTickCount()-start);
}

int main (void)
{
    DC=GetDC(GetDesktopWindow());

    int range;
    for (range = MIN_RANGE; range <= MAX_RANGE; range *= RANGE_MULT) bench(range, 0);
    for (range = MAX_RANGE; range >= MIN_RANGE; range /= RANGE_MULT) bench(range, 0);
    for (range = MIN_RANGE; range <= MAX_RANGE; range *= RANGE_MULT) bench(range, DWM_PAUSE);
    for (range = MAX_RANGE; range >= MIN_RANGE; range /= RANGE_MULT) bench(range, DWM_PAUSE);
    return 0;
}
在禁用Aero的情况下运行相同的程序:

c:\Dev\PHP\_StackOverflow\C++\SlowSetPixel\Release>SlowSetPixel.exe
pause 0 range 100 duration 47
pause 0 range 1000 duration 31
pause 0 range 1000 duration 31
pause 0 range 100 duration 31
pause 20 range 100 duration 63
pause 20 range 1000 duration 47
pause 20 range 1000 duration 47
pause 20 range 100 duration 62
有人偷了我的CPU吗? 是的,我当场抓住了罪犯

这些测试最好在任务管理器打开时使用,以便在任务管理器工作时观察可怕的dwm.exe桌面窗口

在第一次执行过程中,dwm.exe被卡在100%的CPU上,使用我电脑的4个核心之一,其内存消耗上升到了荒谬的程度,从大约28 Mb增加到112 Mb

即使暂停20秒,血腥的DWM甚至还没有消化完像素。这就是为什么测试的第二部分显示了稍长的执行时间

如果没有Aero,SetPixel函数基本上不起任何作用。DC不是无效的,但SetPixel不执行任何可见修改

搞什么鬼? 之所以会发生这种情况,可能是因为有了炫目的全新自Vista桌面界面,最终桌面位图的合成是通过这个dwm.exe进程完成的。每个窗口都有自己的图形缓冲区,dwm.exe会收到任何更改的通知,并重新计算背景中每个像素的最终外观

将像素直接写入桌面窗口基本上破坏了这个小方案,因为一个外部程序访问了dwm.exe的私有游乐场

我不知道微软的人是如何处理这个案子的,但很明显他们并没有以一种有效的方式来处理。 看起来桌面的多个副本被加载到内存中,可能是为了允许一个副本被修改,而其他副本则集成在合成链中

dwm.exe占用的内存量大约是1000*1000 RGBA位图大小的25倍。 测试表明,该量随改性区域的表面而变化

我怀疑这个愚蠢的过程每秒对屏幕进行20或30次采样,并在看到诸如SetPixel调用之类的奇怪情况时创建屏幕修改部分的新副本

这么糟糕的结果,我想知道为什么他们一开始就允许访问桌面DC,只允许人们用10行代码涂抹屏幕

高效的屏幕访问现在需要使用
DirectX为了绕过糟糕的向后兼容性层,您必须使用过时的Win32 GDI操作位图。

好吧,Kuroi neko已经尝试在某种程度上解释了这一点,但我认为确切的原因尚未得到回答

为什么它会随着时间的推移而变慢? ==>因为最终它的顺序是nlogn

如何==>

让我们从setpixel的工作原理开始,但我将以它的工作方式进行讨论。首先也是最重要的任务是参数验证。谷歌提供参数验证或stackexchange的成本。它还包括将屏幕数据映射到设备上下文,然后根据它测试传递的坐标。简言之,这需要时间,应该加以考虑。 像素具有一定的属性;因此,它必须填充一些类似于结构的东西,然后必须创建调色板,然后根据结构填充颜色位,然后需要将调色板映射到设备上下文。下一步,它将需要清理这个像素的混乱,几乎类似的是,下一个像素的工作可能会少一点 现在真正的问题来了:SetPixel是gdi32.dll中的函数,而BOOM,图形子系统驻留在内核模式下!!。因此,对于每个像素,都有Usermode->KernelMode->Usermode的开销,这就是为什么第1点和第2点比通常情况更重要的原因。现在很容易猜测为什么它会随着时间的推移而变慢。 微软有没有试图解决这个问题? 是的,是的,事实上这是由于解决了其他问题而引起的问题。简单地说,在最初的设计中,图形子系统不是内核模式的一部分,而是为了提高性能,他们将其移动到内核模式。 他们尝试了GetEnhMetaFile,它在SetPixel中被明确地称为GetEnhMetaFile 更重要的是->您应该知道何时使用SetPixel。如果你用它做的事情可以用其他不太耗时的机制来完成,那是你的错误,而不是MS。你应该用它来做笔迹分析或类似的事情,在这些事情中,单个或非常少的像素值起作用


你可以用谷歌搜索一下,连续切换10万次模式意味着什么

好吧,Kuroi neko试图在某种程度上解释这一点,但我认为确切的原因尚未得到回答

为什么它会随着时间的推移而变慢? ==>因为最终它的顺序是nlogn

如何==>

让我们从setpixel的工作原理开始,但我将以它的工作方式进行讨论。首先也是最重要的任务是参数验证。谷歌提供参数验证或stackexchange的成本。它还包括将屏幕数据映射到设备上下文,然后根据它测试传递的坐标。简言之,这需要时间,应该加以考虑。 像素具有一定的属性;因此,它必须填充一些类似于结构的东西,然后必须创建调色板,然后根据结构填充颜色位,然后需要将调色板映射到设备上下文。下一步,它将需要清理这个像素的混乱,几乎类似的是,下一个像素的工作可能会少一点 现在真正的问题来了:SetPixel是gdi32.dll中的函数,而BOOM,图形子系统驻留在内核模式下!!。因此,对于每个像素,都有Usermode->KernelMode->Usermode的开销,这就是为什么第1点和第2点比通常情况更重要的原因。现在很容易猜测为什么它会随着时间的推移而变慢。 微软有没有试图解决这个问题? 是的,是的,事实上这是由于解决了其他问题而引起的问题。简单地说,在最初的设计中,图形子系统不是内核模式的一部分,而是为了提高性能,他们将其移动到内核模式。 他们尝试了GetEnhMetaFile,它在SetPixel中被明确地称为GetEnhMetaFile 更重要的是->您应该知道何时使用SetPixel。如果你用它做的事情可以用其他不太耗时的机制来完成,那是你的错误,而不是MS。你应该用它来做笔迹分析或类似的事情,在这些事情中,单个或非常少的像素值起作用


你可以用谷歌搜索一下,连续切换10万次模式意味着什么

printf是时间的一部分,所以可能就是它。试着对它进行评论,看看它是否看起来仍在变慢。SetPixel从来不是在显示器上绘图的最快方式。是的。SetPixel的效率太低,处理器降低时钟频率以降低热量已经是一个简单的解释。@HansPassant如果GetTickCount函数返回时钟周期数,这不会改变代码结果否,GetTickCount不会返回处理器时钟周期数@HansPassant,你真的认为SetPixel对处理器的压力不足以引起热问题,是吗?我相信SetPixel实际上会写入非scre
en缓冲区,然后按位显示到实际屏幕上,尽管这可能是大约20年前Windows的工作方式。桌面管理器是否可能检测到更改,只复制一个更改后的矩形,而该矩形最终会变大,因此需要更长的时间?printf是时间的一部分,因此可能就是这样。试着对它进行评论,看看它是否看起来仍在变慢。SetPixel从来不是在显示器上绘图的最快方式。是的。SetPixel的效率太低,处理器降低时钟频率以降低热量已经是一个简单的解释。@HansPassant如果GetTickCount函数返回时钟周期数,这不会改变代码结果否,GetTickCount不会返回处理器时钟周期数@HansPassant,你真的认为SetPixel对处理器的压力不足以引起热问题吗?我相信SetPixel实际上会写入一个屏幕外缓冲区,然后再写入实际屏幕,尽管这可能是大约20年前Windows的工作方式。桌面管理器是否可能检测到更改,而只复制一个更改的矩形,该矩形最终会变大,因此需要更长的时间?