none
C# 多线程 正则占用 CPU100% RRS feed

  • 问题

  • 多线程正则提取网页源码里的邮箱

    以下这段代码造成CPU占用100%


    Regex rx = new Regex(@"[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
          
     MatchCollection matches = rx.Matches(htmlSource);
          
     foreach (Match match in matches)
       {
        emailStr=match.Value;
        Thread.Sleep(1);
       }
    
    

    若把"RegexOptions.Compiled | RegexOptions.IgnoreCase"去除,则几乎不占CPU资源,但只能提取字母全是大写的邮箱

    若只去掉“RegexOptions.Compiled”,占用CPU的状况无多大改变

     

    参考文章:

    1.http://www.soaspx.com/dotnet/csharp/csharp_20101009_5883.html

    2.http://hi.baidu.com/netkey/blog/item/d20bfbdc56154cabcd116632.html

    3.http://hi.baidu.com/netkey/blog/item/d20bfbdc56154cabcd116632.html 若按其中的方法把正则编译成DLL 再引用,效果也不大


    各位老师觉得该如何处理这个问题?

    2011年8月21日 3:12

答案

  • 您用多线程调用 Regex 时,如果是 Compiled 的话,正则表达式会被 Cache 的,那么由于本身在下面的 foreach 语句去遍历 MatchCollection 的时候会被锁,所以其他线程除了等之外无法做其他事情。还有,Thread.Sleep(1) 会强制导致线程的 Transition,几个东西加起来,CPU 100% 就不是意外了。

    建议:

    1、放一个 static 的变量去让 Regex 痔创建一次,不要用 RegexOptions.Compiled。
    2、您如果不清楚 Thread.Sleep(-1), Thread.Sleep(0) 和 Thread.Sleep(1),您最好不要用它们。直接删掉这句。

    我相信这些建议可以解决 CPU 负载问题。

    另外,请不要轻易怀疑 BCL 的性能问题,凡事先要想想是否是自己的代码的写法导致的问题。.NET 的陷阱还是很多的。。。


    Mark Zhou
    • 已标记为答案 Paul Zhou 2011年8月24日 8:33
    2011年8月22日 8:55

全部回复

  • 在正则中"A-Z0-9"添加个"a-z"试试,然后把"RegexOptions.Compiled | RegexOptions.IgnoreCase"去掉

    比如

    Regex rx = new Regex(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}");

    共同努力,共同提高
    kaedei#live.cn My BLOG
    2011年8月21日 5:23
  • 在正则中"A-Z0-9"添加个"a-z"试试,然后把"RegexOptions.Compiled | RegexOptions.IgnoreCase"去掉

    比如

    Regex rx = new Regex(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}");

    共同努力,共同提高
    kaedei#live.cn My BLOG

    多谢,按你更改的正则表达式可以实现  把"RegexOptions.Compiled | RegexOptions.IgnoreCase"去掉后 提取邮箱 的效果,

    但是占用CPU这一问题仍不能解决。

    另请教"a-z"是什么意思?

    ===========================================================

     

    为什么以下提取源码链接的代码放在同一程序同一位置里却可以很高效的提取 链接,也是用正则,但是却几乎不占用CPU

     public static string[] ExtractLinks(string html)
      {
       Collection<string> urls = new Collection<string>();
       try
       {
        string str = @"(href|HREF)[ ]*=[ ]*[""'][^""'#>]+[""']";
        MatchCollection matches = new Regex(strRef).Matches(html);
    
        foreach (Match match in matches)
        {
         str = match.Value;
           urls.Add(str);
        }
       }
       catch (Exception ex)
       {
        Console.WriteLine(ex.Message);
       }
    
       return urls.ToArray();
      }
    

     

    而我直接信样模仿上面代码 改成如下提取源码里的邮箱的代码,运行时却占用大量CPU资源呢?

     public static string[] ExtractEmails(string html)
      {
       Collection<string> emails = new Collection<string>();
       try
       {
        string str = @"[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}";
        MatchCollection matches = new Regex(strRef, RegexOptions.IgnoreCase).Matches(html);
        foreach (Match match in matches)
        {
         str = match.Value;
         emails.Add(str);
         Thread.Sleep(1);
        }
       }
       catch (Exception ex)
       {
        Console.WriteLine(ex.Message);
       }
       return emails.ToArray();
      }
    
    

    难道是 正则表达式 没有优化导致的?

    我的程序是用多线程来调用上面的代码

     

     

     

     


    2011年8月21日 5:56
  • a-z的意思就是匹配小写字母从a到z

    请试试把 Thread.Sleep(1); 语句去掉


    共同努力,共同提高
    kaedei#live.cn My BLOG
    2011年8月22日 1:38
  • dear

    会导致CPU满载,可能是线程呼叫的写法有问题,请问你如何写??


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2011年8月22日 2:22
  • dear

    会导致CPU满载,可能是线程呼叫的写法有问题,请问你如何写??


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/

    应该不是这个问题,因为我将正则提取邮箱的代码删除后,CPU资源占用 降回到10%以内,


    我的写法是用一个for 循环启动多个线程

     

     
    for (int i = 0; i < ThreadCount; i++)
    {
    CrawlerThread crawler = new rawlerThread(this);
    
    crawler.StatusChanged += new CrawlerStatusChangedEventHandler(CrawlerStatusChanged);
    
    crawler.Start(); 
    }
    
    // 这是借用一个网络上的实例其中线程启动的代码 
    

    我想有可能一个原因是正则表达式的匹配效率问题

    看这贴子,我发的,感觉的我问题没办法解决了。

    http://topic.csdn.net/u/20110821/14/1f2c95a0-527b-47e1-96e2-858e8c40152d.html




    2011年8月22日 3:29
  • 您用多线程调用 Regex 时,如果是 Compiled 的话,正则表达式会被 Cache 的,那么由于本身在下面的 foreach 语句去遍历 MatchCollection 的时候会被锁,所以其他线程除了等之外无法做其他事情。还有,Thread.Sleep(1) 会强制导致线程的 Transition,几个东西加起来,CPU 100% 就不是意外了。

    建议:

    1、放一个 static 的变量去让 Regex 痔创建一次,不要用 RegexOptions.Compiled。
    2、您如果不清楚 Thread.Sleep(-1), Thread.Sleep(0) 和 Thread.Sleep(1),您最好不要用它们。直接删掉这句。

    我相信这些建议可以解决 CPU 负载问题。

    另外,请不要轻易怀疑 BCL 的性能问题,凡事先要想想是否是自己的代码的写法导致的问题。.NET 的陷阱还是很多的。。。


    Mark Zhou
    • 已标记为答案 Paul Zhou 2011年8月24日 8:33
    2011年8月22日 8:55