Loading...

Във форума е въведено ограничение, което позволява на потребителите единствено да разглеждат публикуваните въпроси.

DimoUrumov avatar DimoUrumov 2 Точки

Java precompiled regex pattern performance comparisson

Здравейте,

опитвам се да направя сравнение на производителността на нормален и прекомпилиран регулярен израз. Оказва се (поне според резултатите от теста), че прекомпилираният код е по-бавен?! Можете ли да кажете дали логиката ми е правилна?

Това е кода на класа:

https://pastebin.com/t5QEsR11

А това е кода да теста:

https://pastebin.com/Bf3WeBjc

В крайна сметка ми се изплюва следния резултат:

Created big string

Created test class

PatternBenchmarkTest.testPrecompiled: [measured 10 out of 15 rounds, threads: 1 (sequential)] round: 0.34 [+- 0.04], round.block: 0.00 [+- 0.00], round.gc: 0.00 [+- 0.00], GC.calls: 9, GC.time: 0.76, time.total: 8.93, time.warmup: 5.54, time.bench: 3.39

PatternBenchmarkTest.testNonPrecompiled: [measured 10 out of 15 rounds, threads: 1 (sequential)] round: 0.29 [+- 0.05], round.block: 0.00 [+- 0.00], round.gc: 0.00 [+- 0.00], GC.calls: 5, GC.time: 0.32, time.total: 4.52, time.warmup: 1.63, time.bench: 2.88

0
Module: Java Advanced
RoYaL avatar RoYaL Trainer 6849 Точки

Двата теста правят едно и също по веднъж. Единственият начин да направиш Pattern е да го компилираш. Ако кажеш matches()/split() това вътре ще направи компилиране на шаблон. Едно разделяне или една проверка за съвпадение ще направи точно една компилация на шаблон. Толкова, колкото и ръчното създаване на шаблон чрез компилация. Може би това, което искаш е върху прекомпилирания шаблон да направиш разделянето многократно. После да повториш операцията многократно и без прекомпилиран шаблон.

0
DimoUrumov avatar DimoUrumov 2 Точки

Значи Pattern.compile("\\s+") не компилира нищо?

Все пак още в конструктора извиквам да се компилира шаблона:

public StringSplitter() { this.spacesPattern = Pattern.compile(REGEX_STRING); }

Можеш ли да дадеш пример (в код) как се компилира шаблон?

Благодаря предварително!!!

0
RoYaL avatar RoYaL Trainer 6849 Точки

Компилира. Но и string.split() компилира шаблон, защо не му отвориш кода?:

    public String[] split(String regex, int limit) {
        char ch = 0;
        if (((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ...) {
            int off = 0;
            int next = 0;
            // .. some stuff here
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }

Виждаш ли последни return най-отдолу? Правиш абсолютно същото - компилира шаблон и извиква split() върху него.

Това, което се опитах да ти обясня е че правиш точно ЕДНА операция. Кеширането (в случая прекомпилирането) има смисъл, ако ще го преизползваш. И в двата случая се случва точно една компилация и едно разделяне.

0
DimoUrumov avatar DimoUrumov 2 Точки

Добре. :) Не бях погледнал кода. Но все пак ако използвам прекомпилиран шаблон за многократна операция, би трябвало да е по-бързо, защото в единия случай шаблона се компилира само веднъж, а в другия при всяко извикване на string.split(...);

Промених теста така:

        @Test
	public void testNonPrecompiled() {
		for (int i = 0; i < 10; i++)
			pt.nonPrecompiledTest(bigS);
	}

	@Test
	public void testPrecompiled() {
		for (int i = 0; i < 10; i++)
			pt.precompiledTest(bigS);
	}

При което получавам следния резултат:


Created big string
Created test class
PatternBenchmarkTest.testPrecompiled: [measured 10 out of 15 rounds, threads: 1 (sequential)]
 round: 5.15 [+- 0.16], round.block: 0.00 [+- 0.00], round.gc: 0.00 [+- 0.00], GC.calls: 51, GC.time: 3.33, time.total: 83.03, time.warmup: 31.51, time.bench: 51.52
PatternBenchmarkTest.testNonPrecompiled: [measured 10 out of 15 rounds, threads: 1 (sequential)]
 round: 5.13 [+- 0.07], round.block: 0.00 [+- 0.00], round.gc: 0.00 [+- 0.00], GC.calls: 46, GC.time: 3.10, time.total: 76.73, time.warmup: 25.48, time.bench: 51.25
 

Разликата е пренебрежимо малка или никаква. Това значи ли, че компилатора оптимизира байткода предварително и практически няма по-бърз начин да се използва regex?

0
ppbaev avatar ppbaev 157 Точки

Здрасти,

Тестовете, които си написал са "нечестни". Бавната операция - bottleneck-a - е в създаването и в разделянето на стринга с 10000000 символа.

Компилирането на патърна, който е най-тривиалния възможен - празно място, минава за някакви милисекунди и изобщо не може да се усети на фона на другите операции.

Сложи по-сложен патърн за компилация, смени сплитването да е е само 1, повтори циклите на 10000 и тогава ще има реален резултат от това, което се опитваш да тестваш.

Също е лоша практика да тестваш по този начин 2 различни api-та все едно са еднакви, в случая - Pattern.compile() и String.split(). Това, че в Java едното ползва другото по-никакъв начин не гарантира, че в друг език ще е същото.

0
DimoUrumov avatar DimoUrumov 2 Точки

Идеята ми всъщност е следната:

Искам да проверя дали код (първи вариант), който предварително се компилира веднъж и се използва многократно, е по-бърз от код (втори вариант), който на всеки цикъл трябва да се компилира наново.

Но явно Java кешира по някакъв начин компилирания код от втори вариант и оптимизира алгоритъма до такава степен, че дори (поне при мен) е по-бърз от прекомпилирания и използван многократно код от първи вариант.

Надявам се, че ме разбрахте. :)

0
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.