अंतिम प्रदर्शन: C #

प्रदर्शन मैं उन अनुप्रयोगों के प्रदर्शन को अधिकतम करने के लिए 30 प्रथाओं को साझा करूंगा जिनकी आवश्यकता है। फिर, मैं आपको बताऊंगा कि कैसे मैंने उन्हें एक वाणिज्यिक उत्पाद पर लागू किया और अभूतपूर्व परिणाम हासिल किए!
अनुप्रयोग Microsoft Windows सर्वर के साथ काम करते हुए, Windows प्लेटफ़ॉर्म के लिए C # में लिखा गया था। कोई प्रोफाइलर नहीं - सामग्री विभिन्न तकनीकों के काम की समझ पर आधारित है, इसलिए कई विषय अन्य प्लेटफार्मों और प्रोग्रामिंग भाषाओं के लिए काम आएंगे।

प्रस्तावना


यह सब 2008 में वापस शुरू हुआ - फिर मैंने रिलेशनल डेटाबेस की तुलना और प्रतिकृति करने के कार्यों से निपटना शुरू किया। इस प्रकार के अनुप्रयोगों के लिए मुख्य रूप से उच्च गुणवत्ता वाले प्रदर्शन की आवश्यकता होती है, क्योंकि डेटा का नुकसान या भ्रष्टाचार एक आपदा हो सकता है। दूसरे, डेटाबेस का आकार सैकड़ों और हजारों गीगाबाइट तक पहुंच सकता है, इसलिए एप्लिकेशन को उच्च प्रदर्शन की आवश्यकता होती है।
मुख्य जोर SQL सर्वर पर था, और चूंकि Microsoft ने ODBC ड्राइवरों के लिए सामान्य समर्थन को लंबे समय तक छोड़ दिया है और केवल ADO .NET प्रदाता में पूर्ण कार्यक्षमता प्रदान करता है, आवेदन को .NET फ्रेमवर्क के लिए किसी एक भाषा में लिखे जाने की आवश्यकता है। बेशक, उच्च प्रदर्शन कम्प्यूटिंग और .NET प्लेटफ़ॉर्म का संयोजन कम से कम एक मुस्कुराहट का कारण बनता है, लेकिन निष्कर्ष पर नहीं जाता है।
जब उत्पाद तैयार था, तो परिणाम सभी अपेक्षाओं से अधिक हो गए, और प्रदर्शन बाजार पर सबसे अच्छा समाधानों से कई गुना बेहतर था। इस लेख में, मैं आपके साथ उन मूल सिद्धांतों को साझा करना चाहता हूं जिनका आपको उच्च-प्रदर्शन अनुप्रयोगों को लिखते समय पालन करना चाहिए।

अनुकूलन सिद्धांत


सभी सिद्धांतों को श्रेणियों में वर्गीकृत किया गया है, और उनके विवरण में स्पष्टीकरण के बिना बयान हो सकते हैं, हालांकि, वे सभी तथ्यों और अध्ययनों पर आधारित हैं जो आसानी से इंटरनेट पर पाए जा सकते हैं।
प्रत्येक आइटम में संक्षिप्त जानकारी होती है जो मुख्य बिंदु को प्रदर्शित करती है। सामग्री के संतृप्ति के कारण कुछ विवरणों को उजागर नहीं किया जा सकता है, और प्रत्येक आइटम के लिए आप एक अलग लेख लिख सकते हैं। इसलिए, मैं अत्यधिक अनुशंसा करता हूं कि आप प्रत्येक आइटम के विवरण के साथ खुद को किसी भी उपलब्ध स्रोतों से परिचित करें, उन्हें अभ्यास में लाने से पहले। प्रस्तुत सामग्री और ज्ञान अंतराल की गलतफहमी आपके आवेदन के प्रदर्शन में कम से कम कमी ला सकती है।
सभी कोड उदाहरण तुच्छ हैं, और एक अत्यंत बुनियादी सार को प्रदर्शित करते हैं, और एक विशिष्ट समस्या को हल नहीं करते हैं।

से शुरू करें ...

1. एक अच्छा एल्गोरिथ्म।
सबसे पहले, समस्या के लिए इसे हल करने के लिए सबसे अच्छा एल्गोरिथ्म चुनना आवश्यक है। तभी अनुकूलन किया जा सकता है। यदि एल्गोरिथ्म गलत तरीके से चुना गया है, तो कोई अनुकूलन मदद नहीं करेगा।
विभिन्न तकनीकों के काम का गहराई से ज्ञान सभी अनुकूलन तकनीकों का आधार है। और यह ज्ञान कई संभव लोगों से एक एल्गोरिथ्म चुनने में मदद करता है।

2. कार्य योजना।
यदि आप स्पष्ट रूप से उन सभी कार्यों को तैयार करते हैं जो एल्गोरिथम निष्पादित करता है, तो सबसे पहले, एल्गोरिथम को समझना और उसे कार्यान्वित करना आपके लिए आसान होगा, और दूसरी बात यह है कि आप क्रियाओं का एक ग्राफ बना पाएंगे - इस तरह से आप उनके निष्पादन का एक स्पष्ट क्रम जान पाएंगे और समानांतर में कौन से कार्य किए जा सकते हैं।

3. सूक्ष्म विलंब।
एक निश्चित ऑपरेशन होता है, जिसके निष्पादन का समय F सेकंड लगता है। यदि आप इस समय को केवल 1 माइक्रोसेकंड तक कम कर देते हैं, तो 100 मिलियन पुनरावृत्तियों के लिए आपको 100 सेकंड का लाभ मिलेगा! इस तरह के लगातार संचालन अनुकूलन के लिए पहले उम्मीदवार हैं।

कोड शाखा

4. जब सब कुछ पहले से ज्ञात हो तो "अगर" का उपयोग न करें।
आइए एक ऐसे वर्ग के सरल उदाहरण से शुरू करें जिसमें एक सार्वजनिक तरीका है, और इसका आंतरिक कार्यान्वयन:
कोड उदाहरण
class Example
{
    public void Print(String msg)
    {
        if (msg == null)
            throw new ArgumentNullException();
        PrintInternal(msg);
    }

    private void PrintInternal(String msg)
    {
        if (msg == null)
            throw new ArgumentNullException();
        ...
    }
}


. « », «if» – , . «PrintInternal» «Print», . , , . - YAGNI – , ?
:
void PrintValues(IDataReader dataReader)
{
    while (dataReader.Read())
    {
        for (int i = 0; i < dataReader.FieldCount; i++)
        {
            object value = dataReader.GetValue(i);
            PrintValue(value);
        }
    }
}

void PrintValue(object value)
{
    if (value is int)
        ...
    else if (value is long)
        ...
    else if (value is String)
        ...
    else if ...
}


IDataReader . , «Print», ? , GetSchemaTable. :
delegate void PrintMethod(object value);

void PrintValues(IDataReader dataReader)
{
    PrintMethod[] printers = new PrintMethod[dataReader.FieldCount];
    for (int i = 0; i < printers.Length; i++)
    {
        Type fieldType = dataReader.GetFieldType(i);
        if (fieldType == typeof(int))
            printers[i] = PrintInt;
        else if (fieldType == typeof(long))
            printers[i] = PrintLong;
        else ...
    }

    while (dataReader.Read())
    {
        for (int i = 0; i < printers.Length; i++)
        {
            object value = dataReader.GetValue(i);
            printers[i](value);
        }
    }
}


, , , . , - , , . , Boxing / Unboxing , , .

5. «if».
– « », . – , .
Instruction Scheduling – , . :
int x = a * b;
int y = c ^ d;
int z = x + y;
int w = z - y;

, , . , , . , .
, «if». , , , , , Branch prediction.
: «if»? -1, 0, 1, : int CompareBytes(byte a, byte b)
int CompareBytes(byte a, byte b)
{
    unchecked
    {
        int ab = (int)a - (int)b;
        int ba = (int)b - (int)a;
        return (ab >> 31) | (int)((uint)ba >> 31);
    }
}


, «if». , «if» ( ). , .



6. .


7. .
– «if». , , , - (, Copy N Paste).
– 4-
int power4(int v)
{
    int r = 1;
    r *= v;
    r *= v;
    r *= v;
    r *= v;
    return r;
}


, - N K , N K. .. N/K , K . , , - K .
int power(int v, int N)
{
    int r = 1;
    // Reduce the number of iterations by 4 times.
    for (int loops = N >> 2; loops > 0; loops--)
    {
        r *= v;
        r *= v;
        r *= v;
        r *= v;
    }
    // Process the tail.
    for (int loops = N & 3; loops > 0; loops--)
    {
        r *= v;
    }
    return r;
} 


, . «Loop unwinding» Wikipedia.



8. .
, , – . , ( Monitor lock), (, ManualResetEvent), Interlocked, volatile. , . .
«volatile», .. . , , -, , . – . , stack’ – .. . , . , . , – , , , , . .. .
«volatile» – , , , – . . , «» , . , Interlocked, .
«Volatile» , , , . .
class AsyncWorker
{
    volatile int progress;

    public int Progress
    {
        get
        {
            return progress;
        }
    }

    void DoWork()
    {
        for (this.progress = 0; this.progress < Count; this.progress++)
        {
            ...
        }
    }
}


, UI. «progress» «volatile», , 0. , , .

9. .
ThreadPool, , , . , , – ! , .
2 , 2. 3 :

, , – , . . , . , , , . , , «» , .
, , . , - , . , .

10. .
N , , – . , . F , S . , F S, S F. , , , ( ) , (N x F <= N x S). , , .
K «», , , , K . 1000 , 1000 . , ? , 16 , N x F / 16. F S, N x F / 16 > N x S / 1000. .. , 16 . :
void DoWork(ItemProvider provider)
{
    Batch batch = NextFreeBatch();

    while (true)
    {
        Item item = provider.GetNextItem();
        batch.AddItem(item);

        if (batch.IsFull)
        {
            EnqueueBatchForAsyncProcessing(batch);
            batch = NextFreeBatch();
        }
    }
}

void EnqueueBatchForAsyncProcessing(Batch batch)
{
    lock (this.batchQueue)
        this.batchQueue.Enqueue(batch);
}

void ThreadRoutine()
{
    while (true)
    {
        Batch batch = DequeueBatchForAsyncProcessing();

        foreach (Item item in batch)
            ProcessItem(item);

        RecycleBatch(batch);
    }
}

Batch DequeueBatchForAsyncProcessing()
{
    lock (this.batchQueue)
        return this.batchQueue.Dequeue();
}


, – . , .


11. .
, «» , ? ( ), . «», – , . .. , , , , , . , , « ».
– , - . , , .
, /. Process.ProcessorAffinity ( ), ProcessThread.ProcessorAffinity.
Thread.Priority. , . – Process.PriorityClass.



12. .
, , , . , / «», 512 . «», . Windows, – 4 KiB. , 1 , . / .
, 2 KiB , 1 KiB, 4 KiB , 4 KiB . , . , 2 KiB 3 KiB, KiB , KiB .
. - , , – . , , RAID , .
/, , . FileStream, - 4 KiB. , FileStream bufferSize.
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "GetDiskFreeSpaceW")]
static extern bool GetDiskFreeSpace(string lpRootPathName, out int lpSectorsPerCluster, out int lpBytesPerSector, out int lpNumberOfFreeClusters, out int lpTotalNumberOfClusters);

// Each partition has its own cluster size.
public static int GetClusterSize(string path) {

	int sectorsPerCluster;
	int bytesPerSector;
	int freeClusters;
	int totalClusters;
	int clusterSize = 0;
	if (GetDiskFreeSpace(Path.GetPathRoot(path), out sectorsPerCluster, out bytesPerSector, out freeClusters, out totalClusters))
		clusterSize = bytesPerSector * sectorsPerCluster;
	return clusterSize;
}


MTU (Maximum Transmission Unit) . .

13. .
, Stream … ? , . , FileStream , , . , . , ? ( HDD -.) , , . , .
Stream, , . , (. №9). , . Stream – . Stream. -, ! , . , .
, (, NetworkStream).

14. .
( №13), . , . , . Stream.
.

15. .
, , – . , . , IOPS (Input-Output Operations per Second) – , . , :

, ( ) . , .
, , - LZ (Lempel-Ziv), ( ).



16. , .
, :

, reference types , «ref».

17. .
.NET Framework, , . , – . ( ), , ( main). , , , , .
, «null». , , .
– , .

18. .
– , . , , ( byte[], int[], .). , – . , new , .
stack. stack’ (. CreateThread), , , , .
, , , , Array.Resize. , . , (. 26).
, «byte» «int» :
internal static class ByteArrayReinterpreter
{
    private static IntPtr intArrayTypePtr;

    unsafe static ByteArrayReinterpreter()
    {
        int[] intArray = new int[1];
        fixed (int* ptr = intArray)
            intArrayTypePtr = *(IntPtr*)(((byte*)ptr) - (IntPtr.Size * 2));
        intArray = null;
    }

    public static unsafe int[] AsIntArray(this byte[] array)
    {
        if ((array.Length & 3) != 0)
            throw new ArgumentException("The array length must be multiple of 4.");

        object arrayObj = array;
        int newLength = array.Length >> 2;

        fixed (byte* ptr = array)
        {
            *(IntPtr*)(((byte*)ptr) - (IntPtr.Size * 2)) = intArrayTypePtr;
            *(int*)(((byte*)ptr) - IntPtr.Size) = newLength;
        }

        return (int[])arrayObj;
    }
}

– , , .




19. «unsafe» .
«unsafe» C# , . – int Guid, , , .. unsafe , .

20. .
, . «bool»? 4 32- 8 – 64-. «bool» – . , «byte», «ushort», «uint», «ulong», (. «enum»).
, . «int», 0 10? «byte» .
, , 20 ( 0 1048575) «int» (32 ), 12 , . , . , , ( , ).
int field;
// Decouple numeric and flags
const int NumericMask = ((1 << 20) - 1);
int numeric = field & NumericMask;
MyFlags flags = (MyFlags)(field >> 20);
// Unite numeric and flags back
field = ((int)flags << 20) | numeric;


, . , « » .
, , , , .

21. .
:
struct S
{
    byte a;
    short b;
    short c;
}

5 . , S[], - «b». , «new» , 0x100000 – , , , , 4 8. «b» 0x100001, – 0x100006, – 0x10000B, .. , – « ». x86 x86-64 ( 4 8 ) , .
padding – , . 4 , :
struct S
{
    // offset: 0, size: 4
    byte a;
    byte __padding_byte_1;
    byte __padding_byte_2;
    byte __padding_byte_3;
    // offset: 4, size: 4
    short b;
    byte __padding_byte_4;
    byte __padding_byte_5;
    // offset: 8, size: 4
    short c;
    byte __padding_byte_6;
    byte __padding_byte_7;
    // total size: 12
}


, .NET Framework StructLayoutAttribute. , – , , .
. , , . , . , cache lines – (, 32 ), ( ). «S» 5 , , , 6 ( - 32 ; , , - ). -, – . -, , . , , . «PInvoke for GetLogicalProcessorInformation» StackOverflow .
, , . , . , 4 KiB, 8 KiB . « »? , Windows ? .

22. x86-64.
64- , 64- RAX, RSP, .. , , «long» «int». – ( ), . – «int» 8- , .
Guid. 11 (int, 2 short, 8 byte), 16 . , Equals :
Equals
bool Equals(Guid g)
{
    return g._a == this._a && g._b == this._b && g._c == this._c && g._d == this._d
         && g._e == this._e && g._f == this._f && g._g == this._g && g._h == this._h
         && g._i == this._i && g._j == this._j && g._k == this._k;
}


11 , 4-, «unsafe»:
unsafe bool Equals(Guid g)
{
    fixed (Guid* pg = &this)
    {
        int* p1 = (int*)pg;
        int* p2 = (int*)&g;
        return p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2] && p1[3] == p2[3];
    }
}


x86-64, :
x64
unsafe bool Equals(Guid g)
{
    fixed (Guid* pg = &this)
    {
        long* p1 = (long*)pg;
        long* p2 = (long*)&g;
        return p1[0] == p2[0] && p1[1] == p2[1];
    }
}


11 – -, !

23. .
, , , . , , , . .
x86 CALL RET ( «return»). CALL , RET – , CALL. .. JMP ( «jump») – . , , CALL stack ( IP) JMP, RET stack’ JMP .
, - . , stack, . . ( ), stack’, .
, :
:

1. , Guid :
bool CompareGuids(Guid g1, Guid g2)

, Guid 16 , stack 32 , g1 g2. , :
bool CompareGuids(ref Guid g1, ref Guid g2)

, , , 4 32- , 8 64- . , , , stack ( ).
2. , , , :
int Multiply(int a, int b)
{
    return a * b;
}

void Foo()
{
    int a = 4;
    int b = 5;
    int r = Multiply(a, b);
}


Foo Multiply, a b . , , ! ? №3.
, C++ inline, , . , .NET Framework 4.5 - inline ( inline — ). , assembler, . – Copy Paste.
– , .

24. .
, . . :
class X
{
    virtual void A();
    virtual void B();
}

class Y : X
{
    override void B();
}


: X, Y, X. , X : X.A X.B, Y X.A Y.B. ( X Y), .
– , IntPtr[]. , CALL, , – , .
, . – «sealed» . «sealed» , , -. X Y:
sealed class Y : X
{
    override void B();
}

void Slow(X x)
{
    x.B();
}

void Fast(Y y)
{
    y.B();
}


«Y» , , «B» «Y». Slow «X», «B» «Y» , «X» .
, Fast , «Y» , , «B». , , «B» «Y», . , , , «B» . «B», .



25. Reverse engineering.
, . - ...? , SqlDataReader GetValue «xml» String XmlReader. , «xml» . – , StringComparison.Oridnal . , SqlDataReader, XML . , , . , SqlDataReader ( ), «xml» «varbinary». , , . , , XML , , , ( ) XmlReader , XML.

26. .
- 3D , ( ) , , , , . .
3D 3D . , : , 3D . , - .
. - ? , . , - , – . Full HD (1920x1080) 32- – 8 MiB! , . , , ( 100 ). , FPS .
.NET Framework? , , . , . , – new. 0 null, 0. , – , , . , , – . .. .NET , . , ?
GlobalAlloc ( GMEM_ZEROINIT) GC.AddMemoryPressure, , 0 . , , , , .



27. «Format» «ToString».
String.Format, . String.Concat StringBuilder – . , “{0}” .
, ToString. , DML (INSERT/UPDATE/DELETE; ) SQL Server , - String. 3 !

28. .
T-SQL, . identifier , . Hashset. , , :
HashSet<string> keywords;
String tokenText;
bool isKeyword = keywords.Contains(tokenText.ToUpperInvariant());

:

. «keywords» Hashset<int> , -. , T-SQL String.GetHashCode . , 32- . . T-SQL, . , , , , .. ASCII. .NET UCS2/UTF16 , Unicode 127 code points ASCII, ToUpper ASCII, - , «keyword»!
bool IsKeyword(String tokenText)
{
    int hashCode = 0;

    for (int i = 0; i < tokenText.Length; i++)
    {
        int c = (int)tokenText[i];

        // check upper bound
        if (c > 'z')
            return false;

        // to upper case for Latin letters
        if (c >= 'a')
            c ^= 0x20;

        // a keyword must be of Latin letters, numbers, and underscore
        if ( ! ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
            return false;

        // update hash code
        hashCode = hashCode <op> c;
    }

    return keywords.Contain(hashCode);
}


, ToUpper code points, , . , .

29. !
- . – - . – ? , , , , .
: T-SQL UI . : , , . , , 3 : , , . :

, . , : , , .

30. .
, , . – , :
class Multiplier
{
    public int a, b;
    public int Multiply() { return a * b; }
}

-, «Multiply» , . -, . , , , . , , , .
, , «». , , , , - .


, , ( , ) , 5 . , , – . , , .


. , , ( ) . : staging , production; CMS , – , , , ; ; ..
:
  1. , (, , , ..; database schema)
  2. , ( , ; database data)

, : , – . , , .


6 :
  1. . , «» , , .
  2. . , , , .
  3. . , Customers Customers , Products – Products, . .
  4. . , – . 4 :
    • ( )

    • ( - )
    • ( )
    ( ), , .
  5. , . , , . ( 10 , 5 , 50 , ..)
  6. . , SQL , . , .



, (, UI back-end’, « »). , .
:

2 3 22 , .
  %
(, )2464
(, )1628

, , - «Adventure Works», 185 MiB , 761 .
   %
– (, )
8 99.9% – , , «» . , 75% SqlDataReader, 25% – .
102.24.5
, – (, ; , MiB)6
125 MiB
1.8
98 MiB
3.3
-
, (, ; , MiB)
, . , .
12
36 MiB
2.2
24 MiB
5.4
-
T-SQL – , (, ; , MiB)
2 98 MiB 187 MiB – SSD
21
245 MiB
2
187 MiB
10.5
-
T-SQL , (, )
T-SQL , SQL Server. , SQL SqlCommand .
2
27
1
26
1.7

, , , . , , ( QueryPerformanceCounter). .
: « ? , ?». , , . QA, , , . .. , .
P.S. , , , .


, . , , .NET.
.NET , C++. , C++ Assembler 1.5 2.5 C#. , unmanaged DLL. , C# .
, . , , - . , .NET, , , . , , .
, , , . , , , , .



, :

:




, 28 ( ), «». IEqualityComparer HashSet . , . : SQL Server . , «select» «SELECT» «Select».
GetHashCode. , .. HashSet , Equals. «select» «SELECT». , String.GetHashCode . — String.ToUpperInvariant . , — StringComparer OrdinalIgnoreCase. GetHashCode , .
Equals. . . IEqualityComparer StringComparer.OrdinalIgnoreCase, «select» «SELECT» . , IEqualityComparer HashSet StringComparer.OrdinalIgnoreCase .
?
1) GetHashCode. — , : () - ToUpperInvariant , () - CompareInfo.GetSortKey, SortKey , (? Unicode Collation Algoritm).
2) Equals. - ToUpperInvariant, ( «OrdinalIgnoreCase», «IgnoreCase» , «Ordinal» — ).
ToUpperInvariant?
• ToUpperInvariant , String .
• ToUpperInvariant , (2) ( ) (1) ( SortKey). .. 1 3-, ToUpper ( Invariant) ( Case Mappings). , .
• ( ).
?
• , . .. «1», «», (. 26 — ).
• , Case Mappings Unicode.
• ToUpperCase — : ToUpper, GetHashCode.
• , . Int32 .
• .
• (. 23 — , 24 — )

:
1) HashSet + ToUpperInvariant
2) HashSet + StringComparer.OrdinalIgnoreCase IEqualityComparer
3) — , .
program code
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    partial class Program
    {
        #region Keywords 1 - ToUpperInvariant

        static HashSet<String> keywords1;

        static void InitKeywords1()
        {
            keywords1 = new HashSet<string>();
            keywords1.Add("ABSOLUTE");
            keywords1.Add("ACTION");
            keywords1.Add("ADA");
            keywords1.Add("ADD");
            keywords1.Add("ADMIN");
            keywords1.Add("AFTER");
            keywords1.Add("AGGREGATE");
            keywords1.Add("ALIAS");
            keywords1.Add("ALL");
            keywords1.Add("ALLOCATE");
            keywords1.Add("ALTER");
            keywords1.Add("AND");
            keywords1.Add("ANY");
            keywords1.Add("ARE");
            keywords1.Add("ARRAY");
            keywords1.Add("AS");
            keywords1.Add("ASC");
            keywords1.Add("ASENSITIVE");
            keywords1.Add("ASSERTION");
            keywords1.Add("ASYMMETRIC");
            keywords1.Add("AT");
            keywords1.Add("ATOMIC");
            keywords1.Add("AUTHORIZATION");
            keywords1.Add("AVG");
            keywords1.Add("BACKUP");
            keywords1.Add("BEFORE");
            keywords1.Add("BEGIN");
            keywords1.Add("BETWEEN");
            keywords1.Add("BIGINT");
            keywords1.Add("BINARY");
            keywords1.Add("BIT");
            keywords1.Add("BIT_LENGTH");
            keywords1.Add("BLOB");
            keywords1.Add("BOOLEAN");
            keywords1.Add("BOTH");
            keywords1.Add("BREADTH");
            keywords1.Add("BREAK");
            keywords1.Add("BROWSE");
            keywords1.Add("BULK");
            keywords1.Add("BY");
            keywords1.Add("CALL");
            keywords1.Add("CALLED");
            keywords1.Add("CARDINALITY");
            keywords1.Add("CASCADE");
            keywords1.Add("CASCADED");
            keywords1.Add("CASE");
            keywords1.Add("CAST");
            keywords1.Add("CATALOG");
            keywords1.Add("CHAR");
            keywords1.Add("CHAR_LENGTH");
            keywords1.Add("CHARACTER");
            keywords1.Add("CHARACTER_LENGTH");
            keywords1.Add("CHECK");
            keywords1.Add("CHECKPOINT");
            keywords1.Add("CLASS");
            keywords1.Add("CLOB");
            keywords1.Add("CLOSE");
            keywords1.Add("CLUSTERED");
            keywords1.Add("COALESCE");
            keywords1.Add("COLLATE");
            keywords1.Add("COLLATION");
            keywords1.Add("COLLECT");
            keywords1.Add("COLUMN");
            keywords1.Add("COMMIT");
            keywords1.Add("COMPLETION");
            keywords1.Add("COMPUTE");
            keywords1.Add("CONDITION");
            keywords1.Add("CONNECT");
            keywords1.Add("CONNECTION");
            keywords1.Add("CONSTRAINT");
            keywords1.Add("CONSTRAINTS");
            keywords1.Add("CONSTRUCTOR");
            keywords1.Add("CONTAINS");
            keywords1.Add("CONTAINSTABLE");
            keywords1.Add("CONTINUE");
            keywords1.Add("CONVERT");
            keywords1.Add("CORR");
            keywords1.Add("CORRESPONDING");
            keywords1.Add("COUNT");
            keywords1.Add("COVAR_POP");
            keywords1.Add("COVAR_SAMP");
            keywords1.Add("CREATE");
            keywords1.Add("CROSS");
            keywords1.Add("CUBE");
            keywords1.Add("CUME_DIST");
            keywords1.Add("CURRENT");
            keywords1.Add("CURRENT_CATALOG");
            keywords1.Add("CURRENT_DATE");
            keywords1.Add("CURRENT_DEFAULT_TRANSFORM_GROUP");
            keywords1.Add("CURRENT_PATH");
            keywords1.Add("CURRENT_ROLE");
            keywords1.Add("CURRENT_SCHEMA");
            keywords1.Add("CURRENT_TIME");
            keywords1.Add("CURRENT_TIMESTAMP");
            keywords1.Add("CURRENT_TRANSFORM_GROUP_FOR_TYPE");
            keywords1.Add("CURRENT_USER");
            keywords1.Add("CURSOR");
            keywords1.Add("CYCLE");
            keywords1.Add("DATA");
            keywords1.Add("DATABASE");
            keywords1.Add("DATE");
            keywords1.Add("DATETIME");
            keywords1.Add("DATETIME2");
            keywords1.Add("DATETIMEOFFSET");
            keywords1.Add("DAY");
            keywords1.Add("DBCC");
            keywords1.Add("DEALLOCATE");
            keywords1.Add("DEC");
            keywords1.Add("DECIMAL");
            keywords1.Add("DECLARE");
            keywords1.Add("DEFAULT");
            keywords1.Add("DEFERRABLE");
            keywords1.Add("DEFERRED");
            keywords1.Add("DELETE");
            keywords1.Add("DENY");
            keywords1.Add("DEPTH");
            keywords1.Add("DEREF");
            keywords1.Add("DESC");
            keywords1.Add("DESCRIBE");
            keywords1.Add("DESCRIPTOR");
            keywords1.Add("DESTROY");
            keywords1.Add("DESTRUCTOR");
            keywords1.Add("DETERMINISTIC");
            keywords1.Add("DIAGNOSTICS");
            keywords1.Add("DICTIONARY");
            keywords1.Add("DISCONNECT");
            keywords1.Add("DISK");
            keywords1.Add("DISTINCT");
            keywords1.Add("DISTRIBUTED");
            keywords1.Add("DOMAIN");
            keywords1.Add("DOUBLE");
            keywords1.Add("DROP");
            keywords1.Add("DUMP");
            keywords1.Add("DYNAMIC");
            keywords1.Add("EACH");
            keywords1.Add("ELEMENT");
            keywords1.Add("ELSE");
            keywords1.Add("END");
            keywords1.Add("END-EXEC");
            keywords1.Add("EQUALS");
            keywords1.Add("ERRLVL");
            keywords1.Add("ESCAPE");
            keywords1.Add("EVERY");
            keywords1.Add("EXCEPT");
            keywords1.Add("EXCEPTION");
            keywords1.Add("EXEC");
            keywords1.Add("EXECUTE");
            keywords1.Add("EXISTS");
            keywords1.Add("EXIT");
            keywords1.Add("EXTERNAL");
            keywords1.Add("EXTRACT");
            keywords1.Add("FALSE");
            keywords1.Add("FETCH");
            keywords1.Add("FILE");
            keywords1.Add("FILLFACTOR");
            keywords1.Add("FILTER");
            keywords1.Add("FIRST");
            keywords1.Add("FLOAT");
            keywords1.Add("FOR");
            keywords1.Add("FOREIGN");
            keywords1.Add("FORTRAN");
            keywords1.Add("FOUND");
            keywords1.Add("FREE");
            keywords1.Add("FREETEXT");
            keywords1.Add("FREETEXTTABLE");
            keywords1.Add("FROM");
            keywords1.Add("FULL");
            keywords1.Add("FULLTEXTTABLE");
            keywords1.Add("FUNCTION");
            keywords1.Add("FUSION");
            keywords1.Add("GENERAL");
            keywords1.Add("GEOGRAPHY");
            keywords1.Add("GEOMETRY");
            keywords1.Add("GET");
            keywords1.Add("GLOBAL");
            keywords1.Add("GO");
            keywords1.Add("GOTO");
            keywords1.Add("GRANT");
            keywords1.Add("GROUP");
            keywords1.Add("GROUPING");
            keywords1.Add("HAVING");
            keywords1.Add("HIERACHYID");
            keywords1.Add("HOLD");
            keywords1.Add("HOLDLOCK");
            keywords1.Add("HOST");
            keywords1.Add("HOUR");
            keywords1.Add("IDENTITY");
            keywords1.Add("IDENTITY_INSERT");
            keywords1.Add("IDENTITYCOL");
            keywords1.Add("IF");
            keywords1.Add("IGNORE");
            keywords1.Add("IMAGE");
            keywords1.Add("IMMEDIATE");
            keywords1.Add("IN");
            keywords1.Add("INCLUDE");
            keywords1.Add("INDEX");
            keywords1.Add("INDICATOR");
            keywords1.Add("INITIALIZE");
            keywords1.Add("INITIALLY");
            keywords1.Add("INNER");
            keywords1.Add("INOUT");
            keywords1.Add("INPUT");
            keywords1.Add("INSENSITIVE");
            keywords1.Add("INSERT");
            keywords1.Add("INT");
            keywords1.Add("INTEGER");
            keywords1.Add("INTERSECT");
            keywords1.Add("INTERSECTION");
            keywords1.Add("INTERVAL");
            keywords1.Add("INTO");
            keywords1.Add("IS");
            keywords1.Add("ISOLATION");
            keywords1.Add("ITERATE");
            keywords1.Add("JOIN");
            keywords1.Add("KEY");
            keywords1.Add("KILL");
            keywords1.Add("LANGUAGE");
            keywords1.Add("LARGE");
            keywords1.Add("LAST");
            keywords1.Add("LATERAL");
            keywords1.Add("LEADING");
            keywords1.Add("LEFT");
            keywords1.Add("LESS");
            keywords1.Add("LEVEL");
            keywords1.Add("LIKE");
            keywords1.Add("LIKE_REGEX");
            keywords1.Add("LIMIT");
            keywords1.Add("LINENO");
            keywords1.Add("LN");
            keywords1.Add("LOAD");
            keywords1.Add("LOCAL");
            keywords1.Add("LOCALTIME");
            keywords1.Add("LOCALTIMESTAMP");
            keywords1.Add("LOCATOR");
            keywords1.Add("LOWER");
            keywords1.Add("MAP");
            keywords1.Add("MATCH");
            keywords1.Add("MAX");
            keywords1.Add("MEMBER");
            keywords1.Add("MERGE");
            keywords1.Add("METHOD");
            keywords1.Add("MIN");
            keywords1.Add("MINUTE");
            keywords1.Add("MOD");
            keywords1.Add("MODIFIES");
            keywords1.Add("MODIFY");
            keywords1.Add("MODULE");
            keywords1.Add("MONEY");
            keywords1.Add("MONTH");
            keywords1.Add("MULTISET");
            keywords1.Add("NAMES");
            keywords1.Add("NATIONAL");
            keywords1.Add("NATURAL");
            keywords1.Add("NCHAR");
            keywords1.Add("NCLOB");
            keywords1.Add("NEW");
            keywords1.Add("NEXT");
            keywords1.Add("NO");
            keywords1.Add("NOCHECK");
            keywords1.Add("NOCOUNT");
            keywords1.Add("NONCLUSTERED");
            keywords1.Add("NONE");
            keywords1.Add("NORMALIZE");
            keywords1.Add("NOT");
            keywords1.Add("NTEXT");
            keywords1.Add("NULL");
            keywords1.Add("NULLIF");
            keywords1.Add("NUMERIC");
            keywords1.Add("NVARCHAR");
            keywords1.Add("OBJECT");
            keywords1.Add("OCCURRENCES_REGEX");
            keywords1.Add("OCTET_LENGTH");
            keywords1.Add("OF");
            keywords1.Add("OFF");
            keywords1.Add("OFFSETS");
            keywords1.Add("OLD");
            keywords1.Add("ON");
            keywords1.Add("ONLY");
            keywords1.Add("OPEN");
            keywords1.Add("OPENDATASOURCE");
            keywords1.Add("OPENQUERY");
            keywords1.Add("OPENROWSET");
            keywords1.Add("OPENXML");
            keywords1.Add("OPERATION");
            keywords1.Add("OPTION");
            keywords1.Add("OR");
            keywords1.Add("ORDER");
            keywords1.Add("ORDINALITY");
            keywords1.Add("OUT");
            keywords1.Add("OUTER");
            keywords1.Add("OUTPUT");
            keywords1.Add("OVER");
            keywords1.Add("OVERLAPS");
            keywords1.Add("OVERLAY");
            keywords1.Add("PAD");
            keywords1.Add("PARAMETER");
            keywords1.Add("PARAMETERS");
            keywords1.Add("PARTIAL");
            keywords1.Add("PARTITION");
            keywords1.Add("PASCAL");
            keywords1.Add("PATH");
            keywords1.Add("PERCENT");
            keywords1.Add("PERCENT_RANK");
            keywords1.Add("PERCENTILE_CONT");
            keywords1.Add("PERCENTILE_DISC");
            keywords1.Add("PIVOT");
            keywords1.Add("PLAN");
            keywords1.Add("POSITION");
            keywords1.Add("POSITION_REGEX");
            keywords1.Add("POSTFIX");
            keywords1.Add("PRECISION");
            keywords1.Add("PREFIX");
            keywords1.Add("PREORDER");
            keywords1.Add("PREPARE");
            keywords1.Add("PRESERVE");
            keywords1.Add("PRIMARY");
            keywords1.Add("PRINT");
            keywords1.Add("PRIOR");
            keywords1.Add("PRIVILEGES");
            keywords1.Add("PROC");
            keywords1.Add("PROCEDURE");
            keywords1.Add("PUBLIC");
            keywords1.Add("RAISERROR");
            keywords1.Add("RANGE");
            keywords1.Add("READ");
            keywords1.Add("READS");
            keywords1.Add("READTEXT");
            keywords1.Add("REAL");
            keywords1.Add("RECONFIGURE");
            keywords1.Add("RECURSIVE");
            keywords1.Add("REF");
            keywords1.Add("REFERENCES");
            keywords1.Add("REFERENCING");
            keywords1.Add("REGR_AVGX");
            keywords1.Add("REGR_AVGY");
            keywords1.Add("REGR_COUNT");
            keywords1.Add("REGR_INTERCEPT");
            keywords1.Add("REGR_R2");
            keywords1.Add("REGR_SLOPE");
            keywords1.Add("REGR_SXX");
            keywords1.Add("REGR_SXY");
            keywords1.Add("REGR_SYY");
            keywords1.Add("RELATIVE");
            keywords1.Add("RELEASE");
            keywords1.Add("REPLICATION");
            keywords1.Add("RESTORE");
            keywords1.Add("RESTRICT");
            keywords1.Add("RESULT");
            keywords1.Add("RETURN");
            keywords1.Add("RETURNS");
            keywords1.Add("REVERT");
            keywords1.Add("REVOKE");
            keywords1.Add("RIGHT");
            keywords1.Add("ROLE");
            keywords1.Add("ROLLBACK");
            keywords1.Add("ROLLUP");
            keywords1.Add("ROUTINE");
            keywords1.Add("ROW");
            keywords1.Add("ROWCOUNT");
            keywords1.Add("ROWGUIDCOL");
            keywords1.Add("ROWS");
            keywords1.Add("ROWVERSION");
            keywords1.Add("RULE");
            keywords1.Add("SAVE");
            keywords1.Add("SAVEPOINT");
            keywords1.Add("SCHEMA");
            keywords1.Add("SCOPE");
            keywords1.Add("SCROLL");
            keywords1.Add("SEARCH");
            keywords1.Add("SECOND");
            keywords1.Add("SECTION");
            keywords1.Add("SECURITYAUDIT");
            keywords1.Add("SELECT");
            keywords1.Add("SENSITIVE");
            keywords1.Add("SEQUENCE");
            keywords1.Add("SESSION");
            keywords1.Add("SESSION_USER");
            keywords1.Add("SET");
            keywords1.Add("SETS");
            keywords1.Add("SETUSER");
            keywords1.Add("SHUTDOWN");
            keywords1.Add("SIMILAR");
            keywords1.Add("SIZE");
            keywords1.Add("SMALLDATETIME");
            keywords1.Add("SMALLINT");
            keywords1.Add("SMALLMONEY");
            keywords1.Add("SOME");
            keywords1.Add("SPACE");
            keywords1.Add("SPECIFIC");
            keywords1.Add("SPECIFICTYPE");
            keywords1.Add("SQL");
            keywords1.Add("SQL_VARIANT");
            keywords1.Add("SQLCA");
            keywords1.Add("SQLCODE");
            keywords1.Add("SQLERROR");
            keywords1.Add("SQLEXCEPTION");
            keywords1.Add("SQLSTATE");
            keywords1.Add("SQLWARNING");
            keywords1.Add("START");
            keywords1.Add("STATE");
            keywords1.Add("STATEMENT");
            keywords1.Add("STATIC");
            keywords1.Add("STATISTICS");
            keywords1.Add("STDDEV_POP");
            keywords1.Add("STDDEV_SAMP");
            keywords1.Add("STRUCTURE");
            keywords1.Add("SUBMULTISET");
            keywords1.Add("SUBSTRING");
            keywords1.Add("SUBSTRING_REGEX");
            keywords1.Add("SUM");
            keywords1.Add("SYMMETRIC");
            keywords1.Add("SYSNAME");
            keywords1.Add("SYSTEM");
            keywords1.Add("SYSTEM_USER");
            keywords1.Add("TABLE");
            keywords1.Add("TABLESAMPLE");
            keywords1.Add("TEMPORARY");
            keywords1.Add("TERMINATE");
            keywords1.Add("TEXT");
            keywords1.Add("TEXTSIZE");
            keywords1.Add("THAN");
            keywords1.Add("THEN");
            keywords1.Add("TIME");
            keywords1.Add("TIMESTAMP");
            keywords1.Add("TIMEZONE_HOUR");
            keywords1.Add("TIMEZONE_MINUTE");
            keywords1.Add("TINYINT");
            keywords1.Add("TO");
            keywords1.Add("TOP");
            keywords1.Add("TRAILING");
            keywords1.Add("TRAN");
            keywords1.Add("TRANSACTION");
            keywords1.Add("TRANSLATE");
            keywords1.Add("TRANSLATE_REGEX");
            keywords1.Add("TRANSLATION");
            keywords1.Add("TREAT");
            keywords1.Add("TRIGGER");
            keywords1.Add("TRIM");
            keywords1.Add("TRUE");
            keywords1.Add("TRUNCATE");
            keywords1.Add("TSEQUAL");
            keywords1.Add("UESCAPE");
            keywords1.Add("UNDER");
            keywords1.Add("UNION");
            keywords1.Add("UNIQUE");
            keywords1.Add("UNIQUEIDENTIFIER");
            keywords1.Add("UNKNOWN");
            keywords1.Add("UNNEST");
            keywords1.Add("UNPIVOT");
            keywords1.Add("UPDATE");
            keywords1.Add("UPDATETEXT");
            keywords1.Add("UPPER");
            keywords1.Add("USAGE");
            keywords1.Add("USE");
            keywords1.Add("USER");
            keywords1.Add("USING");
            keywords1.Add("VALUE");
            keywords1.Add("VALUES");
            keywords1.Add("VAR_POP");
            keywords1.Add("VAR_SAMP");
            keywords1.Add("VARBINARY");
            keywords1.Add("VARCHAR");
            keywords1.Add("VARIABLE");
            keywords1.Add("VARYING");
            keywords1.Add("VIEW");
            keywords1.Add("WAITFOR");
            keywords1.Add("WHEN");
            keywords1.Add("WHENEVER");
            keywords1.Add("WHERE");
            keywords1.Add("WHILE");
            keywords1.Add("WIDTH_BUCKET");
            keywords1.Add("WINDOW");
            keywords1.Add("WITH");
            keywords1.Add("WITHIN");
            keywords1.Add("WITHOUT");
            keywords1.Add("WORK");
            keywords1.Add("WRITE");
            keywords1.Add("WRITETEXT");
            keywords1.Add("XML");
            keywords1.Add("XMLAGG");
            keywords1.Add("XMLATTRIBUTES");
            keywords1.Add("XMLBINARY");
            keywords1.Add("XMLCAST");
            keywords1.Add("XMLCOMMENT");
            keywords1.Add("XMLCONCAT");
            keywords1.Add("XMLDOCUMENT");
            keywords1.Add("XMLELEMENT");
            keywords1.Add("XMLEXISTS");
            keywords1.Add("XMLFOREST");
            keywords1.Add("XMLITERATE");
            keywords1.Add("XMLNAMESPACES");
            keywords1.Add("XMLPARSE");
            keywords1.Add("XMLPI");
            keywords1.Add("XMLQUERY");
            keywords1.Add("XMLSERIALIZE");
            keywords1.Add("XMLTABLE");
            keywords1.Add("XMLTEXT");
            keywords1.Add("XMLVALIDATE");
            keywords1.Add("YEAR");
            keywords1.Add("ZONE");
        }

        static bool IsKeyword1(String tokenText)
        {
            return keywords1.Contains(tokenText.ToUpperInvariant());
        }

        #endregion

        #region Keywords 2 - StringComparer

        static HashSet<String> keywords2;

        static void InitKeywords2()
        {
            keywords2 = new HashSet<string>(keywords1, StringComparer.OrdinalIgnoreCase);
        }

        static bool IsKeyword2(String tokenText)
        {
            return keywords2.Contains(tokenText);
        }

        #endregion

        #region Keywords 3 - Good optimized

        static IntPtr gpCaseMapping;
        static IntPtr gpKeywords3;

        unsafe static void InitKeywords3()
        {
            gpKeywords3 = Marshal.AllocCoTaskMem(1293 * 4 * 4);
            int* pHashset3 = (int*)gpKeywords3;
            for (int i = 0; i < 1293 * 4; i++)
                pHashset3[i] = 0;
            foreach (String keyword in keywords1)
            {
                fixed (char* pKeyword = keyword)
                {
                    int hashCode = keyword.GetHashCode();
                    int index = (int)(((uint)hashCode % 1293) << 2);
                    if (pHashset3[index] != 0)
                        index += 2;
                    if (pHashset3[index] != 0)
                        throw new Exception("Solve the collision.");
                    pHashset3[index] = hashCode;
                    pHashset3[index + 1] = (int)pKeyword[0] | ((int)pKeyword[1] << 8) | ((int)pKeyword[2] << 16) | ((int)pKeyword[3] << 24);
                }
            }

            gpCaseMapping = Marshal.AllocCoTaskMem(65536);
            byte* pCaseMapping = (byte*)gpCaseMapping;
            for (int i = 0; i < 65536; i++)
                pCaseMapping[i] = 0;
            for (int i = 'A'; i <= 'Z'; i++)
                pCaseMapping[i] = (byte)i;
            for (int i = 'a'; i <= 'z'; i++)
                pCaseMapping[i] = (byte)(i ^ 0x20);
            pCaseMapping['2'] = (byte)'2';
            pCaseMapping['-'] = (byte)'-';
            pCaseMapping['_'] = (byte)'_';
        }

        unsafe static bool IsKeyword3(String tokenText)
        {
            unchecked
            {
                fixed (char* pString = tokenText)
                {
                    byte* pCaseMapping = (byte*)gpCaseMapping;

                    int num1 = 5381;
                    int num2 = num1;
                    int c1;
                    int c2;
                    char* ptr = pString;
                    int seq = 0;

                    if (tokenText.Length >= 4)
                    {
                        c1 = (int)(*(ushort*)ptr);
                        c2 = (int)(*(ushort*)(ptr + 1));
                        c1 = pCaseMapping[c1];
                        c2 = pCaseMapping[c2];
                        if (c1 == 0 || c2 == 0)
                            return false;
                        seq = (c2 << 8) | c1;
                        num1 = ((num1 << 5) + num1 ^ c1);
                        num2 = ((num2 << 5) + num2 ^ c2);
                        ptr += 2;

                        c1 = (int)(*(ushort*)ptr);
                        c2 = (int)(*(ushort*)(ptr + 1));
                        c1 = pCaseMapping[c1];
                        c2 = pCaseMapping[c2];
                        if (c1 == 0 || c2 == 0)
                            return false;
                        seq |= (c2 << 24) | (c1 << 16);
                        num1 = ((num1 << 5) + num1 ^ c1);
                        num2 = ((num2 << 5) + num2 ^ c2);
                        ptr += 2;

                        for (int loops = (tokenText.Length >> 1) - 2; loops > 0; loops--, ptr += 2)
                        {
                            c1 = (int)(*(ushort*)ptr);
                            c2 = (int)(*(ushort*)(ptr + 1));
                            c1 = pCaseMapping[c1];
                            c2 = pCaseMapping[c2];
                            if (c1 == 0 || c2 == 0)
                                return false;
                            num1 = ((num1 << 5) + num1 ^ c1);
                            num2 = ((num2 << 5) + num2 ^ c2);
                        }

                        if ((tokenText.Length & 1) != 0)
                        {
                            c1 = (int)(*(ushort*)ptr);
                            c1 = pCaseMapping[c1];
                            if (c1 == 0)
                                return false;
                            num1 = ((num1 << 5) + num1 ^ c1);
                        }
                    }
                    else if (tokenText.Length == 3)
                    {
                        c1 = (int)(*(ushort*)ptr);
                        c2 = (int)(*(ushort*)(ptr + 1));
                        c1 = pCaseMapping[c1];
                        c2 = pCaseMapping[c2];
                        if (c1 == 0 || c2 == 0)
                            return false;
                        seq = (c2 << 8) | c1;
                        num1 = ((num1 << 5) + num1 ^ c1);
                        num2 = ((num2 << 5) + num2 ^ c2);

                        c1 = (int)(*(ushort*)(ptr + 2));
                        c1 = pCaseMapping[c1];
                        if (c1 == 0)
                            return false;
                        seq |= (c1 << 16);
                        num1 = ((num1 << 5) + num1 ^ c1);
                    }
                    else if (tokenText.Length == 2)
                    {
                        c1 = (int)(*(ushort*)ptr);
                        c2 = (int)(*(ushort*)(ptr + 1));
                        c1 = pCaseMapping[c1];
                        c2 = pCaseMapping[c2];
                        if (c1 == 0 || c2 == 0)
                            return false;
                        seq = (c2 << 8) | c1;
                        num1 = ((num1 << 5) + num1 ^ c1);
                        num2 = ((num2 << 5) + num2 ^ c2);
                        ptr += 2;
                    }
                    else
                    {
                        return false;
                    }

                    int hashCode = num1 + num2 * 1566083941;
                    int index = (int)(((uint)hashCode % 1293) << 2);
                    int* pHashset3 = (int*)gpKeywords3;
                    return (pHashset3[index + 0] == hashCode && pHashset3[index + 1] == seq)
                        || (pHashset3[index + 2] == hashCode && pHashset3[index + 3] == seq);
                }
            }
        }

        #endregion

        #region Test Data

        static String[] TestTokens = new String[] {
"DECLARE", "@lang", "sysname",
"SELECT", "TOP", "@lang", "Alias", "FROM", "sys", "syslanguages", "WHERE", "lcid",
"IF", "@lang", "IS", "NOT", "NULL", "SET", "LANGUAGE", "@lang",
"SET", "ARITHABORT", "ANSI_PADDING", "ANSI_WARNINGS", "QUOTED_IDENTIFIER",
"NOCOUNT", "CONCAT_NULL_YIELDS_NULL", "ANSI_NULLS", "ON",
"SET", "NUMERIC_ROUNDABORT", "IMPLICIT_TRANSACTIONS", "XACT_ABORT", "OFF",
"SET", "DATEFORMAT", "dmy",
"USE", "AdventureWorks2008R2",
"GO",
"INSERT", "Sales", "SalesOrderHeader", "SalesOrderID", "RevisionNumber", "OrderDate", "DueDate", "ShipDate",
"Status", "OnlineOrderFlag", "PurchaseOrderNumber", "AccountNumber", "CustomerID", "SalesPersonID", "TerritoryID",
"BillToAddressID", "ShipToAddressID", "ShipMethodID", "CreditCardID", "CreditCardApprovalCode", "CurrencyRateID",
"SubTotal", "TaxAmt", "Freight", "Comment", "rowguid", "ModifiedDate", "VALUES",
"ALTER", "TABLE", "dbo", "DatabaseLog", "ADD", "CONSTRAINT", "PK_DatabaseLog_DatabaseLogID", "PRIMARY", "KEY", "NONCLUSTERED",
"DatabaseLogID", "ASC", "WITH", "DATA_COMPRESSION", "NONE",
"EXEC", "sp_addextendedproperty", "dbo", "DatabaseLog", "PK_DatabaseLog_DatabaseLogID",
"GO", "IF", "@@ERROR", "OR", "TRANCOUNT", "BEGIN", "IF", "@@TRANCOUNT", "ROLLBACK", "SET", "NOEXEC", "ON", "END",
"GO", "DBCC", "CHECKIDENT", "RESEED", "GO", "IF", "@@ERROR", "@@TRANCOUNT", "BEGIN", "IF", "@@TRANCOUNT", "ROLLBACK", "SET", "NOEXEC", "ON", "END", "GO"
            };

        #endregion

        #region Timing

        static long _timestamp;

        static void StartTiming()
        {
            _timestamp = Stopwatch.GetTimestamp();
        }

        static double EndTiming()
        {
            return (double)(Stopwatch.GetTimestamp() - _timestamp) / (double)Stopwatch.Frequency;
        }

        #endregion

        unsafe static void DoLexerTests()
        {
            int testCount = 100000;
            int matchCount = 0;
            double time;

            // Test 1
            InitKeywords1();
            StartTiming();
            for (int t = testCount; t > 0; t--)
            {
                matchCount = 0;
                for (int i = 0; i < TestTokens.Length; i++)
                {
                    String identifier = TestTokens[i];
                    if (IsKeyword1(identifier))
                        matchCount++;
                }
            }
            time = EndTiming();
            Console.WriteLine("Test 1 - ToUpper");
            Console.WriteLine("Time:    " + time);
            Console.WriteLine("Matches: " + matchCount);
            Console.WriteLine();

            // Test 2
            InitKeywords2();
            StartTiming();
            for (int t = testCount; t > 0; t--)
            {
                matchCount = 0;
                for (int i = 0; i < TestTokens.Length; i++)
                {
                    String identifier = TestTokens[i];
                    if (IsKeyword2(identifier))
                        matchCount++;
                }
            }
            time = EndTiming();
            Console.WriteLine("Test 2 - StringComparer");
            Console.WriteLine("Time:    " + time);
            Console.WriteLine("Matches: " + matchCount);
            Console.WriteLine();

            // Test 3
            InitKeywords3();
            StartTiming();
            for (int t = testCount; t > 0; t--)
            {
                matchCount = 0;
                for (int i = 0; i < TestTokens.Length; i++)
                {
                    String identifier = TestTokens[i];
                    if (IsKeyword3(identifier))
                        matchCount++;
                }
            }
            time = EndTiming();
            Console.WriteLine("Test 3 - Optimized Code");
            Console.WriteLine("Time:    " + time);
            Console.WriteLine("Matches: " + matchCount);
            Console.WriteLine();
        }
    }
}


, ( ):
ToUpperInvariant2330
IEqualityComparer661
239


C ToUpperInvariant , — , . , .NET Framework ( Windows).
3 , StringComparer, . , StringComparer' C++, C#, . , , , 400 . :
• N3 — . , . — 400 , . . — 10 . 10 , .
• , , . .
• , . , -, . , , . , « ». , , . , IntelliSense. , , …
• — ? , SQL Server, .
• , :
, ,

, ( « , »). , — «», , .

Source: https://habr.com/ru/post/In165729/


All Articles