Chinaunix

标题: PYthon的循环,简直是垃圾啊。 [打印本页]

作者: huangyacong    时间: 2012-04-19 16:14
标题: PYthon的循环,简直是垃圾啊。
有一段代码是这样子的:
while 1:
         go()  # 在循环的时候,统计python脚本每秒能执行多少次。
         time.sleep(0.000005)  #sleep

进过计算,平均每秒才1000次。绝对不会超过1000.
如果把sleep的时间写成time.sleep(0.000001),还是每秒1000次。
奇怪了。难道sleep无效?如果把sleep去掉,确实快,每秒10W以上吧,但是cPU占用100%。(我在循环里进行网络信息收发,100%占用是不可接受的。)
难道python的循环里面无法控制?


作者: anonymous0502    时间: 2012-04-19 16:29
因为sleep精度问题,可以自己google一下,据说好像是精确到15ms还是多少了
作者: huangyacong    时间: 2012-04-19 16:30
后来我把time.sleep改为c版本的usleep,通过python的扩展调用,结果还是一样每秒1000次。奇怪了
作者: foxwb    时间: 2012-04-19 16:47
回复 1# huangyacong


  大概所有的分时系统都到不了你要的精度~~~不管你用什么语言
作者: huangyacong    时间: 2012-04-19 16:50
回复 4# foxwb

至少在c语言下,使用sleep的时候,是有效的吧。为何python就例外哇
   
作者: timespace    时间: 2012-04-19 16:56
这是操作系统实现策略,和python或c没一毛钱关系
Linux能支持的精度就在1毫秒左右
作者: huangyacong    时间: 2012-04-19 17:02
回复 6# timespace


    如果使用c调用usleep(1)一微妙,确实能实现哇
作者: timespace    时间: 2012-04-19 17:46
回复 7# huangyacong
详细说下你的测试方法。

下面是我的实验结果(ubuntu 11.10,cpu i7 3.4GHz, mem 4G):
循环10000次,每次1微妙
执行了五次,可以看到时间介于1~10秒,精度略高于1毫秒,但完全达不到1微妙
随着硬件发展和软件更新,这个精度会逼近,但现在还差很远
  1. #include <stdio.h>
  2. #include <unistd.h>

  3. int main(int argc, char* argv[])
  4. {
  5.         unsigned int cnt = 0;
  6.         while (1)
  7.         {
  8.                 usleep(1);
  9.                 if (++cnt > 10000) break;
  10.         }

  11.         return 0;
  12. }
复制代码
cpp $gcc -g -O2 -Wall usleep.c
cpp $time ./a.out

real        0m4.249s
user        0m0.000s
sys        0m1.176s
cpp $time ./a.out

real        0m2.238s
user        0m0.000s
sys        0m0.664s
cpp $time ./a.out

real        0m1.975s
user        0m0.000s
sys        0m0.604s
cpp $time ./a.out

real        0m7.745s
user        0m0.000s
sys        0m2.296s
cpp $time ./a.out

real        0m3.088s
user        0m0.000s
sys        0m0.876s





   
作者: huangyacong    时间: 2012-04-19 17:56
回复 8# timespace


    哥哥,请不要用c、c++,
如果用c来写,请这么写(伪代码)
int main()
{
     total_count = 0  一共执行的次数
    cur_count = 0  当前执行的次数
    cur_time = time 当前时间
     while 1:
         total_count += 1
       if now_time > cur_time + 300
           tmp_count = total_count  -  cur_count
           tmp_time = now_time -  cur_time
           print  float(tmp_count) *  float(1000) /   float(tmp_time)
          cur_count = total_count
           cur_time = now_time
        usleep(1)
}

print出来的就是每秒循环的TPS。使用c来写,绝对不是1000次每秒。如果把上面的伪代码改为python,最高不过1000次每秒
作者: timespace    时间: 2012-04-19 18:09
回复 9# huangyacong
代码?
结果?
给个有说服力的实例


   
作者: anonymous0502    时间: 2012-04-19 18:13
print放在循环里?
好像以前看到说这种测试不科学,因为print非常耗时。
作者: huangyacong    时间: 2012-04-19 18:15
回复 11# anonymous0502


    是的,只是简单的测试。无法可依忽略不计,即使计算上了,不至于每秒1000次吧
作者: huangyacong    时间: 2012-04-19 18:25
本帖最后由 huangyacong 于 2012-04-19 18:38 编辑

回复 10# timespace


    #include "stdafx.h"
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
        int total_count = 0;// 总共执行的次数
        int cur_count = 0; // 当前记录的次数
        DWORD cur_time = GetTickCount(); // 当前时间
        while(1)
        {
                total_count += 1;
                DWORD now_time = GetTickCount();
                if(now_time > cur_time + 300)
                {
                        int tmp_count = total_count - cur_count;
                        DWORD tmp_time = now_time - cur_time;
                        float oo = (float(tmp_count) * float(1000)) / float(tmp_time);
                        printf("TPS=%f\n",oo);
                        cur_count = total_count;
                        cur_time = now_time;
                }
                Sleep(1);
        }
        return 0;
}

TPS=1000次/s搞错了加上sleep



     



作者: huangyacong    时间: 2012-04-19 18:31
回复 10# timespace


    python 版本,

if __name__ == '__main__':
        import time
        cur_count1 = 0
        count1 = 0
       
        tickcount1 = int(time.time()*1000)
       
        def gettick1(tmp_count):
                #print 'qqqqqq'
                global cur_count1
                global tickcount1
                now_time = int(time.time()*1000)
                #print now_time
                if now_time >= tickcount1 + 300:
                        li_time = now_time - tickcount1
                        li_count = tmp_count - cur_count1
                        li = float(li_count) / (float(li_time)/float(1000))
                        print 'TPS=',li,tmp_count
                        tickcount1 = now_time
                        cur_count1 = tmp_count
                       
        while 1:
                time.sleep(0.001)
                count1 = count1 + 1
                gettick1(count1)

TPS = 983次每秒..
那个time.time()不是很精确,不过也够了
作者: timespace    时间: 2012-04-19 18:35
回复 13# huangyacong
usleep或等价的调用在哪里?



   
作者: timespace    时间: 2012-04-19 18:36
回复 14# huangyacong
Python的结果在预期范围,没有争议
重点把C的版本给我看下


   
作者: timespace    时间: 2012-04-19 18:38
莫非Windows能实现1微妙的sleep,我很好奇。。
作者: tianlijian    时间: 2012-04-19 21:57
学习ing
作者: ttvast    时间: 2012-04-20 15:31
>>> def fs(s):
...     i=0
...     min=0.001
...     intv=1.0/s
...     st=time.time()
...     nt=st
...     while 1:
...             et=time.time()
...             if et-st<intv*i:
...                     time.sleep(min)
...                     continue
...             i+=1
...             if et-st>1:
...                     break
...     print i
...
>>> fs(1)
2
>>> fs(10)
11
>>> fs(100)
101
>>> fs(1000)
1001
>>> fs(10000)
9993
>>> fs(100000)
99938
>>> fs(1000000)
308862
>>>
-------------------------------------------------
以上这段代码可以用来控制代码的执行频率. 当然是不可能靠率精度了, 但是在运行的例子中,可以控制运行次数10w这个粒度上.

当然,如果你想严格做到每个0.01ms执行一次代码, 非实时系统不可能提供这种精度的.
作者: ttvast    时间: 2012-04-20 15:52
The current implementation of nanosleep() is based on the normal kernel timer mechanism, which has a resolution of 1/HZ

更高级的nanosleep 也只能精确到 1/HZ, 也就是说有0.001s已经很不错了
作者: macrossyu    时间: 2012-04-24 00:19
回复 14# huangyacong

在ubuntu 12.04 LTS 上跑这段脚本 sleep改为0.00001,结果如下:

TPS= 8366.66666667 2510
TPS= 8470.0 5051
TPS= 8336.66666667 7552
TPS= 8403.33333333 10073
TPS= 8090.0 12500
TPS= 8636.66666667 15091
TPS= 8463.33333333 17630
TPS= 8613.33333333 20214
TPS= 8146.66666667 22658
TPS= 8300.0 25148
TPS= 8203.33333333 27609
TPS= 8326.66666667 30107
TPS= 8183.33333333 32562
TPS= 8403.33333333 35083
TPS= 8173.33333333 37535
TPS= 8373.33333333 40047
TPS= 8203.33333333 42508

这个sleep还是有作用的。。

难道是楼主电脑的问题?

   
作者: timespace    时间: 2012-04-24 10:28
回复 21# macrossyu
lz的应该是windows
你是Linux


   
作者: txdgtwpv    时间: 2012-04-24 10:30
1. sleep与实现有关,不应该依赖于参数太小的结果(换句话说正常情况下sleep的误差可能都比你想象得大)

2. print是IO操作,耗时

3. 态度要谦逊
作者: shmiya    时间: 2012-05-02 12:53
是不是版本的问题,我的是windows + python3.2.2
time.sleep(0.0001)

output:
TPS= 456407.6433121019 143312
TPS= 427000.0 276963
TPS= 303560.50955414015 372281
TPS= 316795.5271565495 471438
TPS= 377796.178343949 590066
TPS= 344047.9233226837 697753
TPS= 284000.0 786929
TPS= 336801.91693290736 892348
TPS= 608181.5286624203 1083317
TPS= 562156.050955414 1259834
TPS= 477702.875399361 1409355
TPS= 437063.6942675159 1546593
TPS= 379514.37699680513 1665381
作者: huangyacong    时间: 2012-05-03 11:35
回复 24# shmiya


    得出这个数字是不准确的,因为sleep的值是0.0001,这个浮点数精度不够,如果你试试写成sleep(0.0003),会发现结果是一样的,同时某个cpu被占满了,说明sleep没效果,只是多了一次sleep调用,这个调用反而减慢了python的执行速度。

作者: UFFIGHTER    时间: 2012-05-03 11:50
Python到底是不是很烂啊,另外,聊天的诸位有没有3年以上的Python的研发经验?我想了解下Python。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2