2012-07-18 19 views
9

Tôi đang xây dựng một ứng dụng thử nghiệm ứng suất để thu thập các máy chủ và phân tích các phản hồi bằng cách sử dụng bao nhiêu chủ đề mà khách hàng có thể tập hợp. Tôi liên tục tìm thấy bản thân mình throttled bởi bộ sưu tập rác (và/hoặc thiếu nó), và trong nhiều trường hợp, nó đi xuống đến chuỗi mà tôi instantiating chỉ để vượt qua chúng ra một Regex hoặc một thói quen phân tích Xml.Có ai đã triển khai trình phân tích cú pháp Regex và/hoặc Xml xung quanh StringBuilders hoặc Luồng không?

Nếu bạn dịch ngược lớp Regex, bạn sẽ thấy rằng nội, nó sử dụng StringBuilders làm gần như mọi thứ, nhưng bạn không thể vượt qua nó một người thợ xây chuỗi; nó trợ giúp kỹ lưỡng các phương thức riêng trước khi bắt đầu sử dụng chúng, vì vậy các phương thức mở rộng cũng sẽ không giải quyết được. Bạn đang ở trong tình huống tương tự nếu bạn muốn lấy đồ thị đối tượng ra khỏi trình phân tích cú pháp trong System.Xml.Linq.

Đây không phải là trường hợp vượt quá tối ưu hóa theo chiều ngang. Tôi đã xem câu hỏi Regex replacements inside a StringBuilder và các câu hỏi khác. Tôi cũng đã lược tả ứng dụng của mình để xem trần nhà đến từ đâu và sử dụng Regex.Replace() bây giờ thực sự đang giới thiệu chi phí đáng kể trong chuỗi phương pháp mà tôi đang cố gắng truy cập máy chủ với hàng triệu yêu cầu mỗi giờ và kiểm tra phản hồi XML về lỗi và mã chẩn đoán được nhúng. Tôi đã loại bỏ mọi tính không hiệu quả khác để điều chỉnh thông lượng và thậm chí tôi đã cắt giảm rất nhiều chi phí của Regex bằng cách mở rộng StringBuilder để tìm kiếm/thay thế ký tự đại diện khi tôi không cần nhóm chụp hoặc backreferences, nhưng có vẻ như với tôi rằng một người nào đó đã bao bọc một tiện ích phân tích cú pháp Regex và Xml tùy chỉnh, dựa trên Stream, tùy chỉnh ngay bây giờ.

Ok, hãy rót qua, nhưng tôi có phải tự mình làm điều này không?

Cập nhật: Tôi đã tìm thấy cách giải quyết giúp giảm mức tiêu thụ bộ nhớ tối đa từ nhiều gigabyte xuống vài trăm megabyte, vì vậy tôi đăng nó bên dưới. Tôi không thêm nó như là một câu trả lời bởi vì a) Tôi thường ghét làm điều đó, và b) Tôi vẫn muốn tìm hiểu xem ai đó có thời gian để tùy chỉnh StringBuilder để làm Regexes (hoặc ngược lại) trước khi tôi làm.

Trong trường hợp của tôi, tôi không thể sử dụng XmlReader vì luồng mà tôi đang nhập chứa một số nội dung nhị phân không hợp lệ trong các phần tử nhất định. Để phân tích cú pháp XML, tôi phải loại bỏ các phần tử đó. Trước đây tôi đã sử dụng một cá thể Regex được biên dịch tĩnh duy nhất để thực hiện thay thế, và bộ nhớ tiêu thụ này như điên (tôi đang cố xử lý ~ 300 tài liệu 10KB/giây). Thay đổi làm giảm đáng kể mức tiêu thụ là:

  1. Tôi đã thêm mã này StringBuilder Extensions article on CodeProject cho phương thức tiện dụng IndexOf.
  2. Tôi đã thêm một (rất) thô WildcardReplace phương pháp cho phép một ký tự đại diện (* hoặc?) Mỗi ​​invocation
  3. tôi đã thay thế việc sử dụng Regex với một cuộc gọi WildcardReplace() để trống nội dung của các yếu tố vi phạm

Điều này rất nhỏ và được kiểm tra chỉ theo mục đích của riêng tôi; Tôi đã làm cho nó thanh lịch và mạnh mẽ hơn, nhưng YAGNI và tất cả những điều đó, và tôi đang vội vàng. Đây là mã:

/// <summary> 
/// Performs basic wildcard find and replace on a string builder, observing one of two 
/// wildcard characters: * matches any number of characters, or ? matches a single character. 
/// Operates on only one wildcard per invocation; 2 or more wildcards in <paramref name="find"/> 
/// will cause an exception. 
/// All characters in <paramref name="replaceWith"/> are treated as literal parts of 
/// the replacement text. 
/// </summary> 
/// <param name="find"></param> 
/// <param name="replaceWith"></param> 
/// <returns></returns> 
public static StringBuilder WildcardReplace(this StringBuilder sb, string find, string replaceWith) { 
    if (find.Split(new char[] { '*' }).Length > 2 || find.Split(new char[] { '?' }).Length > 2 || (find.Contains("*") && find.Contains("?"))) { 
     throw new ArgumentException("Only one wildcard is supported, but more than one was supplied.", "find"); 
    } 
    // are we matching one character, or any number? 
    bool matchOneCharacter = find.Contains("?"); 
    string[] parts = matchOneCharacter ? 
     find.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries) 
     : find.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); 
    int startItemIdx; 
    int endItemIdx; 
    int newStartIdx = 0; 
    int length; 
    while ((startItemIdx = sb.IndexOf(parts[0], newStartIdx)) > 0 
     && (endItemIdx = sb.IndexOf(parts[1], startItemIdx + parts[0].Length)) > 0) { 
     length = (endItemIdx + parts[1].Length) - startItemIdx; 
     newStartIdx = startItemIdx + replaceWith.Length; 
     // With "?" wildcard, find parameter length should equal the length of its match: 
     if (matchOneCharacter && length > find.Length) 
      break; 
     sb.Remove(startItemIdx, length); 
     sb.Insert(startItemIdx, replaceWith); 
    } 
    return sb; 
} 
+2

Có khả thi trong kịch bản của bạn để lưu dữ liệu thô và phân tích dữ liệu sau này không? Tôi đã nhìn thấy một số loại phân tích đã lấy cách tiếp cận này ... – Andre

+0

@Andre, yeah, đó có thể là một gợi ý tốt, tôi đã tránh nó cho đến nay vì tất cả các logic tôi phải làm sáng tỏ. Chiến lược hiện tại là phân tích cú pháp không đồng bộ mọi thứ, lấy đồ thị đối tượng cần thiết ra khỏi phản hồi và ném nó vào MongoDB để phân tích sâu hơn sau này. Vì vậy, tôi giả sử nếu tôi không thực hiện decompiling tất cả mọi thứ Regex phụ thuộc vào và tùy biến tất cả mọi thứ cần thiết để gọi một .Replace(), đó là lựa chọn tốt nhất tiếp theo. Nếu không ai ho ra một giải pháp trước khi lăn, tôi đoán tôi sẽ phải đưa ra quyết định đó. –

+0

Hai tối ưu hóa bạn không đề cập đến là sử dụng 'RegexOptions.Compiled' cho cụm từ thông dụng của bạn và sử dụng trình thu thập rác của máy chủ. Bạn đã làm cả hai? –

Trả lời

Các vấn đề liên quan