Многопоточное использование Regex - PullRequest
5 голосов
/ 28 сентября 2011

Учитывая следующее из MSDN:

Regex объекты могут быть созданы в любом потоке и могут быть разделены между потоками.

Я обнаружил, что для производительности лучше НЕ для совместного использования экземпляра Regex между потоками при использовании класса ThreadLocal.

Кто-нибудь может объяснить, почему он работает примерно в 5 раз быстрее для локального экземпляра потока?

Вот результаты (на 8-ядерном компьютере):

   Using Regex singleton' returns 3000000 and takes 00:00:01.1005695
   Using thread local Regex' returns 3000000 and takes 00:00:00.2243880

Исходный код:

using System;
using System.Linq;
using System.Threading;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static readonly string str = new string('a', 400);
        static readonly Regex re = new Regex("(a{200})(a{200})", RegexOptions.Compiled);

        static void Test(Func<Regex> regexGettingMethod, string methodDesciption)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            var sum = Enumerable.Repeat(str, 1000000).AsParallel().Select(s => regexGettingMethod().Match(s).Groups.Count).Sum();
            sw.Stop();
            Console.WriteLine("'{0}' returns {1} and takes {2}", methodDesciption, sum, sw.Elapsed);
        }

        static void Main(string[] args)
        {
            Test(() => re, "Using Regex singleton");

            var threadLocalRe = new ThreadLocal<Regex>(() => new Regex(re.ToString(), RegexOptions.Compiled));
            Test(() => threadLocalRe.Value, "Using thread local Regex");

            Console.Write("Press any key");
            Console.ReadKey();
        }
    }
}

1 Ответ

5 голосов
/ 30 сентября 2011

Постановка результатов моего расследования.

Давай ILSpy Regex.Содержит ссылку на RegexRunner.Когда объект Regex совпадает с чем-либо, он блокирует свой RegexRunner.Если есть другой параллельный запрос к тому же объекту Regex, создается другой временный экземпляр RegexRunner.RegexRunner стоит дорого.Чем больше потоков делится объектом Regex, тем больше шансов тратить время на создание временных RegexRunners.Надеюсь, что Microsoft исправит это, обращаясь к эпохе массового параллелизма.

Другое дело: статические члены класса Regex, принимающие строку шаблона в качестве параметра (например, Match.IsMatch (input, pattern)), также должны работать плохо, когда то же самоешаблон сопоставляется в разных потоках.Regex поддерживает кэш RegexRunners.Два одновременных Match.IsMatch () с одним и тем же шаблоном будут пытаться использовать один и тот же RegexRunner, и одному потоку придется создать временный RegexRunner.

Спасибо Уиллу за то, что он дал мне знать, как вы обрабатываете вопросы, заданные темойнашел ответ для.

...