免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5812 | 回复: 17
打印 上一主题 下一主题

求助:Coro多线程采集网页的时候假死问题 [复制链接]

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-09-02 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-08-30 13:48 |只看该作者 |倒序浏览
本帖最后由 laolun 于 2015-08-30 13:48 编辑

现在在做一个项目,需要采集大量的网页,从其中提取信息。
我打算用Coro来实现,但是用的过程中,会出现假死的情况。不是因为内存或者CPU的原因,这个程序不占CPU或者内存,跟网速有关系。网络情况好的时候,几乎不会出现,反之就经常出现。已经写了一个线程来监控其他线程超时的问题,但是问题依然存在。可能我代码写的有问题,大家帮忙看看。谢谢啦!
  1. use strict;
  2. use warnings;
  3. use Coro;
  4. use Coro::Timer;
  5. use Coro::LWP;
  6. use LWP::UserAgent;
  7. use LWP::ConnCache;
  8. use HTTP::Cookies;
  9. use Time::HiRes;
  10. use JSON;
  11. use Data::Dumper;

  12. my @urls=();
  13. open(my $in, "todo.txt") or die $!;
  14. while(<$in>){
  15.         chomp $_;
  16.     push(@urls, $_);
  17. }
  18. close($in);
  19. print scalar(@urls)." pages\n";

  20. my $MAX_THREADS = 10;
  21. my @data_queue;
  22. my @result_queue;
  23. my $processing_count = 0;

  24. foreach (1 .. 10)
  25. {
  26.         async(\&thread_io);
  27. }

  28. # 监视是否线程超时
  29. async{
  30.     while(1){
  31.         Coro::Timer::sleep 10;
  32.         my @coros=Coro::State::list;
  33.         #print Dumper(\@coros);
  34.         my @lwp_coro = grep { $_->desc eq "LWP" } @coros;

  35.         warn sprintf "%s lwp coro found.", scalar @lwp_coro;
  36.         for my $coro (@lwp_coro) {
  37.             my $now=time();
  38.             if ($now > $coro->{timeout_at}) {
  39.                 $coro->cancel("timeout");
  40.                 if(@data_queue){
  41.                                         async(\&thread_io);
  42.                 }
  43.             }
  44.         }
  45.         if(@lwp_coro==0){
  46.             exit;
  47.         }
  48.     }
  49. };


  50. for (@urls)
  51. {
  52.         if ($#data_queue > $MAX_THREADS * 2)
  53.         {
  54.                 Coro::Timer::sleep(0.02);
  55.                 redo;
  56.         }
  57.         push(@data_queue, $_);

  58.         if ($#result_queue > -1)
  59.         {
  60.                 # warn $#result_queue;
  61.                 while ($#result_queue > -1)
  62.                 {
  63.                         my $result = shift(@result_queue);
  64.                         # print "$result\n";
  65.                         append("content.txt", $result."\n");
  66.                 }
  67.         }
  68. }

  69. while ($processing_count > 0 or $#data_queue > -1 or $#result_queue > -1)
  70. {
  71.         while ($#result_queue > -1)
  72.         {
  73.                 my $result = shift(@result_queue);
  74.                 # print "$result\n";
  75.                 append("content.txt", $result."\n");
  76.         }
  77.         
  78.         Coro::Timer::sleep(0.02);
  79. }

  80. print "done";
  81. <STDIN>;

  82. ##########################################################################

  83. sub thread_io{
  84.         my $lwp = LWP::UserAgent->new();
  85.         $lwp->agent("Mozilla/5.0 (Windows NT 6.1; rv:36.0) Gecko/20100101 Firefox/36.0");#设置浏览器属性
  86.         my $conncache = new LWP::ConnCache;
  87.         $lwp->conn_cache($conncache);
  88.         my $cookie_jar = HTTP::Cookies->new(
  89.             file => "cookies",
  90.             autosave => 1,
  91.         );
  92.         $lwp->cookie_jar($cookie_jar);
  93.         $Coro::current->desc("LWP");
  94.         $lwp->timeout(60);
  95.         coro_timeout(60);
  96.         while (1)
  97.         {
  98.                 if ($#data_queue == -1)
  99.                 {
  100.                         Coro::Timer::sleep(1);
  101.                         next;
  102.                 }

  103.                 my $data = shift(@data_queue);
  104.                 print $data."\t";
  105.                 ++$processing_count;
  106.                 my $r = $lwp->get($data);
  107.                 my $status = $r->status_line();
  108.                 my $c=filter($r->content());
  109.                 # push(@result_queue, "$Coro::current $data $status");
  110.                 if($r->is_success){
  111.                     print "success\n";
  112.                     push(@result_queue, "$data\t".dosth($c));
  113.                 }else{
  114.                     print "failed\n";
  115.                     append("failed.txt", $data."\n");
  116.                 }
  117.                 --$processing_count;
  118.         }
  119. }

  120. sub coro_timeout {
  121.     my $timeout = shift;
  122.     my $coro = $Coro::current;
  123.     $coro->{timeout_at} = Time::HiRes::time() + $timeout;
  124.     $coro->on_destroy(sub {
  125.         my $message = shift;
  126.         warn sprintf "coro:%s cancel because %s", $coro->desc, $message;
  127.     });
  128. }

  129. sub dosth{
  130.         my ($c)=@_;
  131.         # 很简单的字符串处理,省略掉了。
  132.         return 1;
  133. }


  134. sub append{
  135.         my($fn,$c)=@_;
  136.         open(my $out, ">>$fn") or die $!;
  137.         print $out $c;
  138.         close($out);
  139. }
  140. sub filter{
  141.         my ($str)=@_;
  142.         $str=~s/^\s+//;
  143.         $str=~s/\s+$//;
  144.         $str=~s/\s+/ /igs;
  145.         return $str;
  146. }
复制代码

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-09-02 06:20:00
2 [报告]
发表于 2015-08-30 14:25 |只看该作者
感觉是访问url的线程发生了阻塞,导致没法调度到监控线程上,所以监控线程也就无效了。
然而,俺并不知道问题出在哪。好悲催,技术好low……

评分

参与人数 1可用积分 +30 收起 理由
王楠w_n + 30 ”每日回帖“积分奖励

查看全部评分

论坛徽章:
16
CU十二周年纪念徽章
日期:2013-10-24 15:41:3415-16赛季CBA联赛之广东
日期:2015-12-23 21:21:55青铜圣斗士
日期:2015-12-05 10:35:30黄金圣斗士
日期:2015-11-26 20:42:16神斗士
日期:2015-11-19 12:47:50每日论坛发贴之星
日期:2015-11-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-18 06:20:002015亚冠之城南
日期:2015-11-10 19:10:492015亚冠之萨济拖拉机
日期:2015-10-28 18:47:282015亚冠之柏太阳神
日期:2015-08-30 17:21:492015亚冠之山东鲁能
日期:2015-07-07 18:48:39摩羯座
日期:2014-08-29 23:01:42
3 [报告]
发表于 2015-08-30 17:19 |只看该作者
本帖最后由 tc1989tc 于 2015-08-30 17:51 编辑

sorry, kancuolege

论坛徽章:
16
CU十二周年纪念徽章
日期:2013-10-24 15:41:3415-16赛季CBA联赛之广东
日期:2015-12-23 21:21:55青铜圣斗士
日期:2015-12-05 10:35:30黄金圣斗士
日期:2015-11-26 20:42:16神斗士
日期:2015-11-19 12:47:50每日论坛发贴之星
日期:2015-11-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-18 06:20:002015亚冠之城南
日期:2015-11-10 19:10:492015亚冠之萨济拖拉机
日期:2015-10-28 18:47:282015亚冠之柏太阳神
日期:2015-08-30 17:21:492015亚冠之山东鲁能
日期:2015-07-07 18:48:39摩羯座
日期:2014-08-29 23:01:42
4 [报告]
发表于 2015-08-30 17:21 |只看该作者
本帖最后由 tc1989tc 于 2015-08-30 17:53 编辑


是不是线程cancel的问题啊
有个cancel_safe安全函数 用用试一试

评分

参与人数 1可用积分 +30 收起 理由
王楠w_n + 30 每日回帖积分奖励

查看全部评分

论坛徽章:
16
CU十二周年纪念徽章
日期:2013-10-24 15:41:3415-16赛季CBA联赛之广东
日期:2015-12-23 21:21:55青铜圣斗士
日期:2015-12-05 10:35:30黄金圣斗士
日期:2015-11-26 20:42:16神斗士
日期:2015-11-19 12:47:50每日论坛发贴之星
日期:2015-11-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-18 06:20:002015亚冠之城南
日期:2015-11-10 19:10:492015亚冠之萨济拖拉机
日期:2015-10-28 18:47:282015亚冠之柏太阳神
日期:2015-08-30 17:21:492015亚冠之山东鲁能
日期:2015-07-07 18:48:39摩羯座
日期:2014-08-29 23:01:42
5 [报告]
发表于 2015-08-30 18:05 |只看该作者
在获取url的时候$coro->ready 一下看啊

感觉即使发生阻塞 coro调度线程都会把自己加入的ready队列啊
还有就是确认你的监控线程是不是自己exit啦  exit之前打个日志看看嘛。。

评分

参与人数 1可用积分 +30 收起 理由
王楠w_n + 30 每日回帖积分奖励

查看全部评分

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
6 [报告]
发表于 2015-08-30 20:17 |只看该作者
Perl 内置并不支持并发。第三方模块实现的并发,是真的并发吗?有真正支持并发(内置)的语言,要是我的话,就用支持并发的语言实现,并发涉及到底层线程和进程的调度,如果出了问题,不是语言本身的能力,很难跟踪调试。

最稳定的工具是语言,也是最可信赖的东西,要使用第三方模块,必须能跟踪其中的问题。

评分

参与人数 1可用积分 +30 收起 理由
王楠w_n + 30 每日回帖积分奖励

查看全部评分

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-09-02 06:20:00
7 [报告]
发表于 2015-08-30 23:04 |只看该作者
谢谢兄的建议。查了下文档,稍微纠正下,应该是 safe_cancel 。从兄的建议中得到了启发,就是线程退出的方法问题。文档中关于线程退出的方法有好几种,等会我都试下。
谢谢!
回复 4# tc1989tc


   

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-09-02 06:20:00
8 [报告]
发表于 2015-08-30 23:09 |只看该作者
你是说在:
  1. my $data = shift(@data_queue);
复制代码
之后加上一句
  1. $Coro::current->ready
复制代码
?
tc1989tc 发表于 2015-08-30 18:05
在获取url的时候$coro->ready 一下看啊

感觉即使发生阻塞 coro调度线程都会把自己加入的ready队列啊

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-09-02 06:20:00
9 [报告]
发表于 2015-08-30 23:13 |只看该作者
我估计你说的是这一句:
  1. my $r = $lwp->get($data);
复制代码
如果是这一句堵了,不大好弄啊。
回复 5# tc1989tc


   

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-09-02 06:20:00
10 [报告]
发表于 2015-08-30 23:19 |只看该作者
本帖最后由 laolun 于 2015-08-30 23:20 编辑

我也有这种感觉。
现在网络很顺畅,毫无问题。不会出现卡死的情况,监控线程偶尔会杀掉几个超时的线程。
所以问题可能出在第三方模块(Coro)的get方法上
  1. $lwp->get($url);
复制代码
,而这可能跟它模块本身的写法有关,而在外部不好监控和调试。
回复 6# 104359176


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP