답변:
RegexOptions.Compiled
LCG (Lightweight Code Generation)를 사용하여 정규식 표현식을 IL로 컴파일하도록 정규식 엔진에 지시합니다 . 이 편집은 객체를 구성하는 동안 발생하며 속도가 크게 느려집니다. 결과적으로 정규 표현식을 사용한 일치가 더 빠릅니다.
이 플래그를 지정하지 않으면 정규식은 "통역 됨"으로 간주됩니다.
이 예제를 보자 :
public static void TimeAction(string description, int times, Action func)
{
// warmup
func();
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < times; i++)
{
func();
}
watch.Stop();
Console.Write(description);
Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}
static void Main(string[] args)
{
var simple = "^\\d+$";
var medium = @"^((to|from)\W)?(?<url>http://[\w\.:]+)/questions/(?<questionId>\d+)(/(\w|-)*)?(/(?<answerId>\d+))?";
var complex = @"^(([^<>()[\]\\.,;:\s@""]+"
+ @"(\.[^<>()[\]\\.,;:\s@""]+)*)|("".+""))@"
+ @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
+ @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
+ @"[a-zA-Z]{2,}))$";
string[] numbers = new string[] {"1","two", "8378373", "38737", "3873783z"};
string[] emails = new string[] { "sam@sam.com", "sss@s", "sjg@ddd.com.au.au", "onelongemail@oneverylongemail.com" };
foreach (var item in new[] {
new {Pattern = simple, Matches = numbers, Name = "Simple number match"},
new {Pattern = medium, Matches = emails, Name = "Simple email match"},
new {Pattern = complex, Matches = emails, Name = "Complex email match"}
})
{
int i = 0;
Regex regex;
TimeAction(item.Name + " interpreted uncached single match (x1000)", 1000, () =>
{
regex = new Regex(item.Pattern);
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
i = 0;
TimeAction(item.Name + " compiled uncached single match (x1000)", 1000, () =>
{
regex = new Regex(item.Pattern, RegexOptions.Compiled);
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
regex = new Regex(item.Pattern);
i = 0;
TimeAction(item.Name + " prepared interpreted match (x1000000)", 1000000, () =>
{
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
regex = new Regex(item.Pattern, RegexOptions.Compiled);
i = 0;
TimeAction(item.Name + " prepared compiled match (x1000000)", 1000000, () =>
{
regex.Match(item.Matches[i++ % item.Matches.Length]);
});
}
}
3 가지 정규 표현식에 대해 4 가지 테스트를 수행합니다. 먼저 한 번의 오프 매치 (컴파일 대 비 컴파일)를 테스트합니다 . 둘째, 동일한 정규 표현식을 재사용하는 반복 일치를 테스트합니다.
내 컴퓨터의 결과 (릴리스로 컴파일되고 디버거가 연결되지 않음)
타입 | 플랫폼 | 사소한 번호 | 간단한 이메일 확인 | 내선 이메일 확인 -------------------------------------------------- ---------------------------- 해석 | x86 | 4ms | 26ms | 31ms 해석 | x64 | 5ms | 29ms | 35ms 컴파일 | x86 | 913ms | 3775ms | 4487ms 컴파일 | x64 | 3300ms | 21985 ms | 22793ms
타입 | 플랫폼 | 사소한 번호 | 간단한 이메일 확인 | 내선 이메일 확인 -------------------------------------------------- ---------------------------- 해석 | x86 | 422ms | 461 ms | 2122ms 해석 | x64 | 436ms | 463 ms | 2167ms 컴파일 | x86 | 279ms | 166ms | 1268ms 컴파일 | x64 | 281ms | 176ms | 1180ms
이 결과 는 객체 를 재사용하는 경우 컴파일 된 정규식이 최대 60 % 더 빠를 수 있음을 보여줍니다 Regex
. 그러나 어떤 경우에는 구성이 3 배 이상 느릴 수 있습니다 .
또한 정규식을 컴파일 할 때 x64 버전 의 .NET이 5-6 배 느려질 수 있음을 보여줍니다 .
다음 과 같은 경우 컴파일 된 버전 을 사용하는 것이 좋습니다.
정규 표현식 엔진에는 Regex
클래스 의 정적 메소드를 사용하여 테스트 한 마지막 15 개의 정규 표현식을 보유하는 LRU 캐시가 포함되어 있습니다 .
예를 들어 Regex.Replace
, Regex.Match
등 모든 사용 정규식 캐시.
캐시 크기를 설정하여 늘릴 수 있습니다 Regex.CacheSize
. 응용 프로그램 수명주기 동안 언제든지 크기 변경을 허용합니다.
새로운 정규 표현식은 Regex 클래스 의 정적 도우미 에 의해서만 캐시 됩니다 . 그러나 객체를 생성하면 캐시가 점검되고 (재사용 및 범프) 생성하는 정규식 은 캐시에 추가되지 않습니다 .
이 캐시는 간단한 LRU 캐시이며 간단한 이중 링크 목록을 사용하여 구현됩니다. 5000으로 늘리고 정적 도우미에서 5000 개의 다른 호출을 사용하는 경우 모든 정규식 구성은 5000 개의 항목을 크롤링하여 이전에 캐시되었는지 확인합니다. 검사 주위 에 잠금 장치 가 있으므로 검사를 통해 병렬 처리가 줄어들고 스레드 차단이 발생할 수 있습니다.
숫자는 이와 같은 경우로부터 자신을 보호하기 위해 상당히 낮게 설정되어 있지만 경우에 따라 숫자를 늘리는 것 외에는 선택의 여지가 없습니다.
내 강력한 권장 사항 은 옵션을 정적 도우미에게 전달 하지 않습니다RegexOptions.Compiled
.
예를 들면 다음과 같습니다.
\\ WARNING: bad code
Regex.IsMatch("10000", @"\\d+", RegexOptions.Compiled)
그 이유는 LRU 캐시를 놓칠 위험이 너무 커서 컴파일 비용 이 매우 많이 듭니다 . 또한 의존하는 라이브러리가 무엇을하는지 모를 수 있으므로 캐시의 가능한 최대 크기 를 제어하거나 예측하는 능력이 거의 없습니다 .
참조 : BCL 팀 블로그
참고 : 이것은 .NET 2.0 및 .NET 4.0과 관련이 있습니다. 4.5에는 일부 변경 사항이있을 수 있으며 이로 인해 수정 될 수 있습니다.
Compiled
웹 사이트 코드에서 종종 정적 (응용 프로그램 전체) Regex
객체를 저장하는 곳에서 사용 합니다. 따라서 Regex
IIS는 응용 프로그램을 시작할 때 한 번만 구성한 다음 수천 번 재사용해야합니다. 응용 프로그램이 자주 다시 시작되지 않는 한 잘 작동합니다.
BCL 팀 블로그의이 항목은 " 정규 표현식 성능 "에 대한 개요를 제공합니다 .
간단히 말해 세 가지 유형의 정규 표현식이 있습니다 (각각 이전 유형보다 빠르게 실행 됨).
해석
빠르게 생성하고 실행 속도가 느립니다.
컴파일 (당신이 묻는 것)
실행 속도가 느리고 실행 속도가 빠릅니다 (루프 실행에 적합)
사전 컴파일
앱 컴파일 타임에 생성 (런타임 생성 페널티 없음), 빠른 실행
따라서 정규 표현식을 한 번만 실행하거나 앱의 성능이 중요하지 않은 섹션 (예 : 사용자 입력 유효성 검사)에서 실행하려면 옵션 1을 사용하는 것이 좋습니다.
루프에서 정규식을 실행하려면 (예 : 파일의 라인 별 구문 분석) 옵션 2를 사용해야합니다.
앱에 변경되지 않고 많이 사용되는 정규 표현식이 많은 경우 옵션 3을 사용할 수 있습니다.
CompileModule
. 젠장, 나는 새로운 플랫폼을 더 깊이 들여다 볼 필요가있다.
.NET 2.0 이후 정규 표현식의 성능은 컴파일되지 않은 정규 표현식의 MRU 캐시로 향상되었습니다. 정규식 라이브러리 코드는 더 이상 매번 컴파일되지 않은 동일한 정규식을 더 이상 해석하지 않습니다.
따라서 잠재적으로 더 큰 성과가 페널티 컴파일하고 즉석에서 정규 표현식으로. 로드 시간이 느려지는 것 외에도 시스템은 더 많은 메모리를 사용하여 정규식을 opcode로 컴파일합니다.
기본적으로 현재 조언은 정규식을 컴파일하지 않거나 별도의 어셈블리로 미리 컴파일하는 것입니다.
Ref : BCL 팀 블로그 정규 표현식 성능 [David Gutierrez]
아래 코드가 re.compile 함수의 개념을 이해하는 데 도움이되기를 바랍니다.
import re
x="""101 COM Computers
205 MAT Mathematics
189 ENG English
222 SCI Science
333 TA Tamil
5555 KA Kannada
6666 TL Telugu
777777 FR French
"""
#compile reg expression / successfully compiled regex can be used in any regex
#functions
find_subject_code=re.compile("\d+",re.M)
#using compiled regex in regex function way - 1
out=find_subject_code.findall(x)
print(out)
#using compiled regex in regex function way - 2
out=re.findall(find_numbers,x)
print(out)
#few more eg:
#find subject name
find_subjectnames=re.compile("(\w+$)",re.M)
out=find_subjectnames.findall(x)
print(out)
#find subject SHORT name
find_subject_short_names=re.compile("[A-Z]{2,3}",re.M)
out=find_subject_short_names.findall(x)
print(out)