酷!學園

技術討論區 => 程式討論版 => 主題作者是: logichom 於 2014-10-26 00:11

主題: [Perl]單一perl程式消耗大量cpu
作者: logichom2014-10-26 00:11
之前撰寫程式碼時只在乎perl程式消耗多少記憶體
而忽略CPU的使用情況
而目前單一一隻程式就占用CPU約65%的使用量
想請問有什麼辦法可將該程式消耗的CPU使用量降低?

為方便大家隔空抓藥
簡單說明一下該程式的功能:
1.連線至mysql資料庫建立資料表
2.開檔
3.無限迴圈讀檔
4.如果讀到關鍵訊息
5.建立與資料庫連線
6.寫入資料到資料庫
7.回到3.

主題: Re: 單一perl程式消耗大量cpu
作者: hoyo2014-10-26 00:14
無限迴圈內加個 sleep 讓程式睡一下就可以了

perl 不熟,自己找找相關指令
主題: Re: 單一perl程式消耗大量cpu
作者: logichom2014-10-26 13:26
無限迴圈內加個 sleep 讓程式睡一下就可以了

perl 不熟,自己找找相關指令
好奇如果讓程式睡一下會不會因此錯過log?
主題: Re: 單一perl程式消耗大量cpu
作者: hoyo2014-10-26 14:55
2. 開檔

開什麼檔? Log ???

不讀取會馬上刪除?

調整一下程式或是目前的程式寫法就可以解決的問題,不能解決就耗 CPU 啊
主題: Re: 單一perl程式消耗大量cpu
作者: gwstudy2014-10-26 17:13
為方便大家隔空抓藥
簡單說明一下該程式的功能:
...
3.無限迴圈讀檔
4.如果讀到關鍵訊息
...
7.回到3.

我想問題出在 4 (他是待罪羔羊)。
如果沒讀到時,它會做什麼? 我想程式可能是直接跳到 7,7 馬上再跳到 3 -> 4
cpu 什麼也沒做,一直在跳來跳去。
主題: Re: 單一perl程式消耗大量cpu
作者: netman2014-10-26 20:30
用  nice 或  batch 去跑?
主題: Re: 單一perl程式消耗大量cpu
作者: logichom2014-10-27 09:11
2. 開檔

開什麼檔? Log ???

不讀取會馬上刪除?

調整一下程式或是目前的程式寫法就可以解決的問題,不能解決就耗 CPU 啊
是log檔沒錯
目前想到是在某個時段將該天log讀一次
一天讀一次log然後寫到資料庫去應該loading就不會重了
但是讀的時間要抓好
不然漏掉訊息就糟了
主題: Re: 單一perl程式消耗大量cpu
作者: logichom2014-10-27 09:17
為方便大家隔空抓藥
簡單說明一下該程式的功能:
...
3.無限迴圈讀檔
4.如果讀到關鍵訊息
...
7.回到3.

我想問題出在 4 (他是待罪羔羊)。
如果沒讀到時,它會做什麼? 我想程式可能是直接跳到 7,7 馬上再跳到 3 -> 4
cpu 什麼也沒做,一直在跳來跳去。
是的
但是光讀檔跟跳來跳去就吃cpu loading
不太能理解
至於為什麼要讀到關鍵訊息
因為log是由設備丟出來
其中參雜很多不必要的訊息
過濾就成為必要手段了
主題: Re: 單一perl程式消耗大量cpu
作者: hoyo2014-10-27 09:43
一個東西讓你從右手拿到左手

明明就沒東西給你,你也要不斷的做動作,難道不會累嗎?

重點是,不斷的重複動作,就「一定」可以接收到資料?  誰跟你說的
主題: Re: 單一perl程式消耗大量cpu
作者: gwstudy2014-10-27 13:22
喔,原來是這地方不理解。
cpu 只要在執行就會耗能,即使只是一個"跳"的動作。
你可以試試看,寫個程式,只是一直跳,什麼也不做。

// 語法忘了,請自行修正
while <TRUE> {
}
它會做到死,cpu loading 會飆高。

但是光讀檔跟跳來跳去就吃cpu loading
不太能理解
主題: Re: 單一perl程式消耗大量cpu
作者: Yamaka2014-10-27 13:43
一開始 hoyo 老大就給解答了,樓主試過了嗎?

如果因為『空』迴圈 CPU 吃太重
最簡單的解法就是在迴圈裡加 sleep
下面兩個指令(ctrl-c停止)
自己比較看看吧

$ perl -e 'while(1){}'

$ perl -e 'use Time::HiRes qw(usleep); while(1){usleep(500);}'
主題: Re: 單一perl程式消耗大量cpu
作者: hongbin2014-10-27 22:28
或者可用 cpulimit  限制程式執行的cpu 使用率
http://cpulimit.sourceforge.net/
主題: Re: 單一perl程式消耗大量cpu
作者: twu22014-10-28 09:58
sleep 加上去試看看不就知道了嗎?





經驗上來說, 就算只停個 1ms 的時間, 也會大幅改進吃 cpu 的時間.
問題是... 如果是這麼重要又急的事情, 似乎不是用這種寫法吧.... 通常這類的寫法, 停個 1s 再處理都算快的了.
主題: Re: 單一perl程式消耗大量cpu
作者: logichom2014-10-28 10:02
這邊有個難言之隱
為什麼不加sleep
為什麼要用無限迴圈

因為受限於log
要過濾log是用時間來判斷
但是要判斷時間如果不讓他一直更新就無法取得最新的時間
除非有不用無限迴圈的方法
這個我還在思考中...
先謝謝各位前輩了
主題: Re: 單一perl程式消耗大量cpu
作者: logichom2014-10-28 10:07
sleep 加上去試看看不就知道了嗎?





經驗上來說, 就算只停個 1ms 的時間, 也會大幅改進吃 cpu 的時間.
問題是... 如果是這麼重要又急的事情, 似乎不是用這種寫法吧.... 通常這類的寫法, 停個 1s 再處理都算快的了.

謝謝提醒了我
因為我一直以為sleep只能到秒
後來查了一下有可以到毫秒的用法
http://stackoverflow.com/questions/896904/how-do-i-sleep-for-a-millisecond-in-perl (http://stackoverflow.com/questions/896904/how-do-i-sleep-for-a-millisecond-in-perl)
主題: Re: 單一perl程式消耗大量cpu
作者: davidju2014-10-28 13:42
有無程式碼PO來瞧瞧 :)
主題: Re: 單一perl程式消耗大量cpu
作者: gwstudy2014-10-28 13:52
不是難言之隱,只是你用的方法不好,。

while <> {
}

或 tail -f logfile | yourprog.pl

建議你多看範例才能快速上手,自己摸索很容易卡關。
還有 sleep 是要減少 cpu 跳來跳去避免 cpu load 太高,你又想只睡幾毫秒,那又回到老問題了: cpu load 很高。
方法不好要改方法,不要去補丁,浪費你 coding 的生命。
主題: Re: 單一perl程式消耗大量cpu
作者: netman2014-10-28 23:35
最新的時間用 date 來取也可以,可以取過去5分鐘或1分鐘啊 ...
不用依賴 log
主題: Re: 單一perl程式消耗大量cpu
作者: netman2014-10-28 23:37
或是交給 cron 去跑,如果 log 沒變更,就直接結束。
如果擔心跑太久到下次cron還沒跑完,就用 lock file 來防止。
主題: Re: 單一perl程式消耗大量cpu
作者: logichom2014-10-28 23:56
程式碼在此:
引用
my $dsn="DBI:mysql:database=search;host=localhost";
my $userid="root";
my $password="password";
my $dbh=DBI->connect($dsn,$userid,$password) or print "Could not connect to database: $DBI::errstr";

eval{
$dbh->do('CREATE TABLE mytable(SN integer auto_increment primary key,Month CHAR(3),Day CHAR(2),
Time CHAR(8),MAC CHAR(17),Username VARCHAR(64))');
$dbh->disconnect or warn $dbh->errstr;
};
warn $@ if $@;

my $file1="/var/log/xxx/mytable.log";
eval{ open(LOGFILE, $file1) or die "Can't open file , $!\n"; };
print "Error:$@" if $@;   
for(;;)
{
   while(<LOGFILE>)
   {
      chomp $_;
      ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
      my $dates = strftime "%H:%M",localtime;
       
        @array=split(' ', $_);
        if(@array[0] == "$months[$mon]" && @array[1] == "$mday" && @array[2] =~ /$dates/)
        {      
        if($_ =~ /Action=do/)
        {
         @array = split(' ', $_);
         $month=@array[0];
         $day=@array[1];
         $time=@array[2];
          
         @array = split(',', $_);         
         $mac=substr @array[3],7;
         $mac1=substr($mac,0,2).":".substr($mac,3,2).":".substr($mac,6,2).":"
         .substr($mac,9,2).":".substr($mac,12,2).":".substr($mac,15,2);
         $mac1=lc $mac1;     
         $username=substr @array[6],5;
         $username =~ s/[\r\n]//;
                           
         if($mac1 =~ /(?:[A-Fa-f0-9]{2}[:-]){5}(?:[A-Fa-f0-9]{2})/)
         {
         eval{   
         $dbh=DBI->connect($dsn,$userid,$password) or print "Could not connect to database:$DBI::errstr";
         $dbh->do("set names utf8");
         my $sth=$dbh->prepare("INSERT INTO mytable(Month,Day,Time,MAC,Username)values(?,?,?,?,?)");               
         $sth->execute($month,$day,$time,$mac1,$username)or print $DBI::errstr;
         $sth->finish();         
         $dbh->disconnect or warn $dbh->errstr;
         };
         warn $@ if $@;
         }         
        }
      }
      $month="";
      $day="";
      $time="";
      $mac="";
      $username="";
      $dates="";
      
   }
    $rotate=strftime "%H:%M:%S",localtime;
    if($rotate eq "03:XX:XX")
    {
          close(LOGFILE);
          sleep 1;
          eval{ open(LOGFILE, $file1) or die "Can't open file , $!\n"; };
          print "Error:$@" if $@;
    }   
}   
主題: Re: 單一perl程式消耗大量cpu
作者: gwstudy2014-10-29 03:45
方法有好幾種,我針對你寫法不好的地方提供一個樣本,參考看看。

程式: print.pl
===============
#!/usr/bin/perl
while(<STDIN>){
   print $_ ."\n";
}
===============

在 terminal 打
touch my.log; tail -f my.log | ./print.pl

再開一個 terminal, 輸入:
echo AA >> my.log
你會看到第一個 terminal 會輸出 AA

上面這樣寫,cpu 很輕鬆,不會有 load 飆高的現象。
主題: Re: 單一perl程式消耗大量cpu
作者: davidju2014-10-29 13:57
在 chomp $_ 的上頭加上 sleep (1)  8) 8)

操練前先休息一下
主題: Re: 單一perl程式消耗大量cpu
作者: dark2014-10-30 19:37
1. 接收資料部分使用 while read , 倒建議交給 socket
perl 開 socket 很容易 , 緩衝一定有餘又不浪費資源

2. 開 socket 接資料跟讀檔是兩件事
使用 tail -f  , 若檔案重頭開始 (如 syslog 的 logrot?? <- 怎麼拼 ??)
那將會有很多行送不出來

您 /var/log/xxx/mytable.log 是怎麼來的須留意
若是 syslog() , printk() ... 這類呼叫 log deamon 寫入
那讀檔部分就交由 linux 內建 log server 較佳

若不是 , 讀檔部分要考慮重複 , 漏掉問題 ... 那將是整體中最浪費資源的

主題: Re: 單一perl程式消耗大量cpu
作者: logichom2014-10-31 09:19
1. 接收資料部分使用 while read , 倒建議交給 socket
perl 開 socket 很容易 , 緩衝一定有餘又不浪費資源

2. 開 socket 接資料跟讀檔是兩件事
使用 tail -f  , 若檔案重頭開始 (如 syslog 的 logrot?? <- 怎麼拼 ??)
那將會有很多行送不出來

您 /var/log/xxx/mytable.log 是怎麼來的須留意
若是 syslog() , printk() ... 這類呼叫 log deamon 寫入
那讀檔部分就交由 linux 內建 log server 較佳

若不是 , 讀檔部分要考慮重複 , 漏掉問題 ... 那將是整體中最浪費資源的
檔案是由設備丟出來的,我的server再去設定接收該log,該log會在半夜做輪替,然後我的程式要在輪替完從新開檔讀檔
主題: Re: 單一perl程式消耗大量cpu
作者: netman2014-11-01 09:24
logrotate 可以設定 prerotate 跟 postrotate 的 script 啊~
主題: Re: 單一perl程式消耗大量cpu
作者: asako2014-11-29 11:47
組合一下 tail -f | grep | awk | mysql -e
cpu 會非常低
主題: Re: 單一perl程式消耗大量cpu
作者: rainday2014-11-29 17:10
如dark說所
做成daemon加上socket才是最有效率的方式
如果流量與動作不多,pipe方式是能加減的用