Upload
it-people
View
137
Download
4
Embed Size (px)
Citation preview
Неасимптотическиеоптимизации
• Предположим, что асимптотика алгоритма уже наилучшая
• Но надо еще быстрее
Задача 1. Регулярные выражения
• Алгоритм по регулярному выражению строит какую-то автоматоподобную структуру
public class Node{
public map<char, Node> jumps;public bool accepted;…
}
bool Match(string str){
Node current = start;for (int i = 0; i < str.Length; ++i){
current = current.jumps[str[i]];if (current == null)
return false;}return current.accepted;
}
public abstract class Node
{
public bool accepted;
public abstract Node Jump(char c);
…
}
public class NodeImpl : Node
{
private map<char, Node> jumps;
public override Node Jump(char c)
{
return jumps[c];
}
}
bool Match(string str)
{
Node current = start;
for (int i = 0; i < str.Length; ++i)
{
current = current.Jump(str[i]);
if (current == null)
return false;
}
return current.accepted;
}
public class NodeWithThreeChildren : Node
{
private Node child_a;
private Node child_b;
private Node child_c;
public override Node Jump(char c)
{
if (c == 'a')
return child_a;
if (c == 'b')
return child_b;
if (c == 'c')
return child_c;
return null;
}
}
public class NodeJumpByAZ : Node{
private Node child;
public override Node Jump(char c){
if (c >= 'a' && c <= 'z')return child;
if (c >= 'A' && c <= 'Z')return child;
return null;}
}
public class NodeJumpSegment : Node{
private Node[] children;private char start;private char finish;
public override Node Jump(char c){
if (c >= start && c <= finish)return children[c - start];
return null;}
}
bool Match(string str)
{
Node current = start;
for (int i = 0; i < str.Length; ++i)
{
current = current.Jump(str[i]);
if (current == null)
return false;
}
return current.accepted;
}
bool Match(string str){
Node current = start;for (int i = 0; i < str.Length; ++i){
if (current == s1){
// Реализация метода Jump для s1}else if (current == s2){
// Реализация метода Jump для s2}…else if (current == sn){
// Реализация метода Jump для sn}else
return false;}return current.accepted;
}
if (current == s1)
{
if (str[i] == 'a')
current = s2;
else if (str[i] == 'b')
current = s3;
else …
}
bool Match(string str){
int idx = 0;int len = str.Length;char c;
_1: if (idx >= len)return false;
c = str[idx++];if (c == '+' || c == '-')
goto _2;if (c >= '0' && c <= '9')
goto _3;return false;
_2: if (idx >= len)return false;
c = str[idx++];if (c >= '0' && c <= '9')
goto _3;return false;
_3: if (idx >= len)return true;
c = str[idx++];if (c >= '0' && c <= '9')
goto _3;if (c == '.')
goto _4;return false;
_4: if (idx >= len)return true;
c = str[idx++];if (c >= '0' && c <= '9')
goto _4;return false;
}
Способы кодогенерации
• Пишем текст в файл и вызываем компилятор
• Байткод (JASM, IL, ASM)
• Roslyn (.NET)
13.1
22.6
1
1.9
10.3
C# Regex compiled
C# Regex
Inlined автомат
Автомат без хэш-таблицы
Автомат с хэш-таблицей
Результаты
Время
Total = AttrA + AttrB – Abs(AttrC) – Abs(AttrD) + AttrE
/File
/Document
/Income
<Income Total="100" AttrA="1"
AttrB="2" AttrC="-3"
AttrD="4" AttrE="5" />
Алгоритм
• Парсим настройки в дерево:
• Данные кладем в map<>
Sum
AttrA
AttrB
Negate Abs AttrC
Negate Abs AttrD
AttrE
public abstract class Operation
{
public abstract decimal Exec(map<string, decimal> arguments);
}
public class ArgumentOperation : Operation
{
private string operand;
public override decimal Exec(map<string, decimal> arguments)
{
return arguments[operand];
}
}
public abstract class Operation
{
public abstract decimal Exec(map<string, decimal> arguments);
}
public class SumOperation : Operation
{
private Operation[] children;
public override decimal Exec(map<string, decimal> arguments)
{
decimal result = 0;
foreach (Operation child in children)
result = result + child.Exec(arguments);
return result;
}
}
// Чтение данных
arguments["Total"] = 100;
arguments["AttrA"] = 1;
arguments["AttrB"] = 2;
arguments["AttrC"] = -3;
arguments["AttrD"] = 4;
arguments["AttrE"] = 5;
…
// Проверка
void Check()
{
var expected = arguments["Total"];
var actual =
SumOperation.Exec(
ArgumentOperation.Exec("AttrA"),
ArgumentOperation.Exec("AttrB"),
NegateOperation.Exec(
AbsOperation.Exec(
ArgumentOperation.Exec("AttrC"))
),
NegateOperation.Exec(
AbsOperation.Exec(
ArgumentOperation.Exec("AttrD"))
),
ArgumentOperation.Exec("AttrE")
);
if(expected != actual)
RaiseError();
}
public class Closure{
public decimal Total;public decimal AttrA;public decimal AttrB;public decimal AttrC;public decimal AttrD;public decimal AttrE;
}
// Чтение данныхclosure.Total = 100;closure.AttrA = 1;closure.AttrB = 2;closure.AttrC = -3;closure.AttrD = 4;closure.AttrE = 5;…
// Проверкаvoid Check(){
var expected = closure.Total;var actual = closure.AttrA
+ closure.AttrB– Math.Abs(closure.AttrC)- Math.Abs(closure.AttrD)+ closure.AttrE;
if(expected != actual)RaiseError();
}
Результаты
• Этот пример взят из сервиса форм Контур Экстерна
• Нужно валидировать xml-файлы размером до нескольких гигабайт
Результаты
• Этот пример взят из сервиса форм Контур Экстерна
• Нужно валидировать xml-файлы размером до нескольких гигабайт
• После применения метода кодогенерациивалидация работает в 20 раз быстрее
Вывод
• Преимущества• Прирост производительности
• Код красивый и оптимальный
• Недостатки• Технически сложная задача
Вывод
• Преимущества• Прирост производительности
• Код красивый и оптимальный
• Недостатки• Технически сложная задача
• Большее время разогрева
Вывод
• Преимущества• Прирост производительности
• Код красивый и оптимальный
• Недостатки• Технически сложная задача
• Большее время разогрева
• Возможен прирост использования памяти