Кто-нибудь реализовал парсер Regex и / или Xml вокруг StringBuilders или Streams?

Я создаю клиент для стресс-тестирования, который отбивает серверы и анализирует ответы, используя столько потоков, сколько может собрать клиент. Я постоянно оказываюсь задушенным сборщиком мусора (и / или его отсутствием), и в большинстве случаев это сводится к строкам, которые я создаю только для того, чтобы передать их в процедуру синтаксического анализа Regex или Xml.

Если вы декомпилируете класс Regex, вы увидите, чтоinternally, он использует StringBuilders, чтобы делать почти все, но вы не можетеpass это струнный строитель; он услужливо погружается в приватные методы перед тем, как начать их использовать, поэтому методы расширения также не решат его. Вы находитесь в аналогичной ситуации, если хотите получить граф объектов из синтаксического анализатора в System.Xml.Linq.

Это не случай педантичной чрезмерной оптимизации заранее. Я посмотрел наRegex замены внутри StringBuilder вопрос и др. Я также профилировал свое приложение, чтобы увидеть, откуда берутся потолки, и используюRegex.Replace() сейчас действительно вносятся значительные издержки в цепочку методов, где я пытаюсь поразить сервер миллионами запросов в час и проверить ответы XML на наличие ошибок и встроенных диагностических кодов. Я уже избавился практически от любой другой неэффективности, которая ограничивает пропускную способность, и я даже сократил многие накладные расходы на Regex, расширив StringBuilder для выполнения поиска / замены с помощью подстановочных знаков, когда мне не нужны группы захвата или обратные ссылки, но мне кажется, что кто-то уже обернул пользовательскую утилиту синтаксического анализа Regex и Xml на основе StringBuilder (или, еще лучше, Stream).

Хорошо, так разглагольствовать, но я собираюсь сделать это сам?

Update: Я нашел обходной путь, который снизил пиковое потребление памяти с нескольких гигабайт до нескольких сотен мегабайт, поэтому я разместил его ниже. Я не добавляю его в качестве ответа, потому что а) я вообще ненавижу это делать и б) я все еще хочу выяснить, тратит ли кто-нибудь время, чтобы настроить StringBuilder для выполнения регулярных выражений (или наоборот), прежде чем я это сделаю.

В моем случае я не мог использовать XmlReader, потому что поток, который я принимаю, содержит недопустимый двоичный контент в определенных элементах. Чтобы разобрать XML, я должен очистить эти элементы. Ранее я использовал один статический скомпилированный экземпляр Regex для замены, и это потребляло память как безумный (я пытаюсь обработать ~ 300 10 КБ документов / сек). Изменение, которое резко сократило потребление, было:

I added the code from this StringBuilder Extensions article on CodeProject for the handy IndexOf method. I added a (very) crude WildcardReplace method that allows one wildcard character (* or ?) per invocation I replaced the Regex usage with a WildcardReplace() call to empty the contents of the offending elements

Это очень неуместно и проверено только настолько, насколько этого требуют мои собственные цели; Я бы сделал его более элегантным и мощным, но ЯГНИ и все такое, и я тороплюсь. Вот код:

/// <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;
}

Ответы на вопрос(3)

Ваш ответ на вопрос