字符串的耗时操作

在一个新闻采集的项目中,处理一条信息时CPU竟然耗尽,后查找原因发现在一个do...while循环里耗时竟超过20分钟。一般而言,一百万的循环耗时一般为一秒。因此如果一个循环就能将CPU耗尽长达20多分钟,那么循环里一定会有其它非循环操作在作怪。原处理方法如下:

/// <summary>
        /// 格式化Html正文.
        /// </summary>
        /// <param name="Content">Html文档内容。</param>
        /// <param name="Buf">结果缓冲区。</param>
        public static void FormatHtml(string Content, HtmlBufBase Buf)
        {
            if (string.IsNullOrEmpty(Content))
                return;
            // 过滤前面未处理的标记
            int TagEnd = Content.IndexOf('>', 0);
            if (TagEnd == -1)
                TagEnd = 0;
            else
            {
                //处理Title中的HTML标签
                int pos = GetNextTagStartPosition(Content, 0);
                if (pos > -1 && TagEnd > pos)
                    TagEnd = 0;
                else
                    TagEnd++;
            }
            bool bIsNotInHideTag = true;  // 是否不在隐藏的标记内容中
            bool bIsNotInStyle = true;
            string HideTag = null;
            string LastTag = null;
            do
            {
                if (Content.Contains("国家统计局服务业调查中心"))
                {
                }
                // 找标记开始
                int TagStart = GetNextTagStartPosition(Content, TagEnd);
                if (TagStart == -1)
                    TagStart = Content.Length;// 达到结尾
                else if (Content.IndexOf("!--", TagStart) == TagStart+1)   // 判断是否是注释
                {
                    TagEnd = Content.IndexOf("-->", TagStart)+3;
                    if (TagStart == -1)
                        TagStart = Content.Length;
                    continue;
                }
                // 转换内容
                if (bIsNotInHideTag && bIsNotInStyle)
                    Buf.AppendText(Content.Substring(TagEnd, TagStart - TagEnd));
                // 找标记结束
                TagEnd = GetNextTagEndPosition(Content, TagStart);
                if (TagEnd > -1)
                {
                    TagEnd++;
                    TagStart++;
                    string TagInfo;
                    string Tag = GetTagAndTagInfo(Content, TagEnd, TagStart, out TagInfo);
 
                    if (Tag == "script")  // 脚本开始
                    {
                        int scriptEndPos = Content.IndexOf("</script>", TagStart, StringComparison.OrdinalIgnoreCase);
                        if (scriptEndPos > 0)
                        {
                            TagEnd = scriptEndPos + 9;
                        }
                        else
                        {
                            TagEnd = Content.Length;
                        }
                    }
                    else if (Tag == "style")
                    {
                        bIsNotInStyle = false;
                    }
                    else if (Tag == "/style")
                    {
                        bIsNotInStyle = true;
                    }
                    else if (TagInfo.ToLower().IndexOf("display:none") > 0)
                    {
                        bIsNotInHideTag = false;
                        HideTag = Tag;
                    }
                    else if (Tag == "/" + HideTag)
                    {
                        bIsNotInHideTag = true;
                        HideTag = null;
                    }
                    else
                        Buf.AppendTag(Tag, TagInfo);
 
                    //else if (Tag == "base")
                    //    BaseUrl = GetBaseUrl(TagInfo);
                    LastTag = Tag;
                }
                else
                    break;
            } while (true);
            Buf.ReFormatText();
        }
 
最近查找到有一条语句特别耗时即
 else if (Content.IndexOf("!--", TagStart) == TagStart+1)   // 判断是否是注释,这个字符串的查找都是全文查找,肯定特别耗时,这条语句的功能是判断标签是否是注释,因此没必要去判断”!--“只需要判断!即可。因此使用字符查找即可,改动如下:
 else if (Content[TagStart+1] == '!')   // 判断是否是注释
改成上面语句后CPU尽管会耗尽,但耗时只需30秒。
深入追究一下,可知字符的查找应该是数组的查找,为什么不直接使用数组下标呢?改动如下:
Content[TagStart + 1] == '!'
改后测试一下,在本方法中的两万多次循环中只需要60毫秒。
最后程序改动如下:
 /// <summary>
        /// 格式化Html正文.
        /// </summary>
        /// <param name="Content">Html文档内容。</param>
        /// <param name="Buf">结果缓冲区。</param>
        public static void FormatHtml(string Content, HtmlBufBase Buf)
        {
            if (string.IsNullOrEmpty(Content))
                return;
 
            // 过滤前面未处理的标记
            int TagEnd = Content.IndexOf('>', 0);
            if (TagEnd == -1)
                TagEnd = 0;
            else
            {
                //处理Title中的HTML标签
                int pos = GetNextTagStartPosition(Content, 0);
                if (pos > -1 && TagEnd > pos)
                    TagEnd = 0;
                else
                    TagEnd++;
            }
            bool bIsNotInHideTag = true;  // 是否不在隐藏的标记内容中
            bool bIsNotInStyle = true;
 
            string HideTag = null;
            string LastTag = null;
            do
            {
                // 找标记开始
                int TagStart = GetNextTagStartPosition(Content, TagEnd);
                if (TagStart == -1)
                    TagStart = Content.Length;// 达到结尾
              
                // 转换内容
                if (bIsNotInHideTag && bIsNotInStyle)
                    Buf.AppendText(Content.Substring(TagEnd, TagStart - TagEnd));
                // 判断是否是注释
                if (TagStart != -1 && TagStart < Content.Length && Content[TagStart + 1] == '!')   
                {
                    TagEnd = Content.IndexOf("-->", TagStart);
                    if (TagEnd == -1)//没有找到注释的结束标记
                    {
                        TagEnd = Content.Length;
                    }
                    else//有注释的结束标记,跳过本标记
                    {
                        TagEnd = TagEnd + 3;
                        continue;
                    }
                }
                // 找标记结束
                TagEnd = GetNextTagEndPosition(Content, TagStart);
                if (TagEnd > -1)
                {
                    TagEnd++;
                    TagStart++;
                    string TagInfo;
                    string Tag = GetTagAndTagInfo(Content, TagEnd, TagStart, out TagInfo);
 
                    if (Tag == "script")  // 脚本开始
                    {
                        int scriptEndPos = Content.IndexOf("</script>", TagStart, StringComparison.OrdinalIgnoreCase);
                        if (scriptEndPos > 0)
                        {
                            TagEnd = scriptEndPos + 9;
                        }
                        else
                        {
                            TagEnd = Content.Length;
                        }
                    }
                    else if (Tag == "style")
                    {
                        bIsNotInStyle = false;
                    }
                    else if (Tag == "/style")
                    {
                        bIsNotInStyle = true;
                    }
                    else if (TagInfo.ToLower().IndexOf("display:none") > 0)
                    {
                        bIsNotInHideTag = false;
                        HideTag = Tag;
                    }
                    else if (Tag == "/" + HideTag)
                    {
                        bIsNotInHideTag = true;
                        HideTag = null;
                    }
                    else
                        Buf.AppendTag(Tag, TagInfo);
 
                    //else if (Tag == "base")
                    //    BaseUrl = GetBaseUrl(TagInfo);
                    LastTag = Tag;
                }
                else
                    break;
            } while (true);
            Buf.ReFormatText();
        }
posted @ 2018-09-14 09:58  陈苏乾  阅读(450)  评论(0编辑  收藏  举报