2012-05-07 20 views
19

मैं कार्ड संयोजन स्कोर (7 में से 5 सर्वश्रेष्ठ कार्ड) प्राप्त करने के लिए "रेडब्ल्यू हाथ मूल्यांकनकर्ता" दृष्टिकोण का उपयोग करने की कोशिश कर रहा हूं। हालांकि मेरे पास इस विधि के साथ प्रदर्शन समस्या है। सूत्रों के मुताबिक - इस दृष्टिकोण का उपयोग प्रति सेकंड 300 मिलियन से अधिक हाथों का मूल्यांकन करना संभव होना चाहिए! मेरा परिणाम 1.5 सेकंड में 10 मिलों है, जो कई बार धीमा है।तेज पोकर हाथ मूल्यांकन

के पीछे "RayW हाथ मूल्यांकनकर्ता" विचार पीछा कर रहा है:

दो प्लस टू मूल्यांकनकर्ता कुछ तीस-दो मिलियन प्रविष्टियों (32,487,834 सटीक होना करने के लिए) से युक्त एक बड़ी लुकअप तालिका के होते हैं। दिए गए 7-कार्ड पोकर हाथ को देखने के लिए क्रम में, आप इस तालिका के माध्यम से एक पथ का पता लगाते हैं, प्रति कार्ड एक लुकअप करते हैं।

namespace eval 
{ 
public struct TPTEvaluator 
{ 
    public static int[] _lut; 

    public static unsafe void Init() // to load a table 
    { 
     _lut = new int[32487834]; 
     FileInfo lutFileInfo = new FileInfo("HandRanks.dat"); 
     if (!lutFileInfo.Exists) 
     {throw new Exception("Handranks.dat not found");} 

     FileStream lutFile = new FileStream("HandRanks.dat", FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096); 

     byte[] tempBuffer = new byte[32487834 * 4]; 
     lutFile.Read(tempBuffer, 0, 32487834 * 4); 

     fixed (int* pLut = _lut) 
     { Marshal.Copy(tempBuffer, 0, (IntPtr)pLut, 32487834 * 4);} 
     tempBuffer = null; 
    } 

    public unsafe static int LookupHand(int[] cards) // to get a hand strength 
    { 
     fixed (int* pLut = _lut) 
     { 
      int p = pLut[53 + cards[0]]; 
      p = pLut[p + cards[1]]; 
      p = pLut[p + cards[2]]; 
      p = pLut[p + cards[3]]; 
      p = pLut[p + cards[4]]; 
      p = pLut[p + cards[5]]; 
      return pLut[p + cards[6]]; 
     } 
    } 
} 

}

और है कि मैं तरीका बताया गया है: जब आप पिछले कार्ड के लिए मिलता है, इसलिए प्राप्त मूल्य हाथ

यहाँ

की आधिकारिक तुल्यता मूल्य कैसे कोड लग रहा है की तरह है इस दृष्टिकोण का परीक्षण करें:

private void button4_Click(object sender, EventArgs e) 
    { 
     int[] str = new int[] { 52, 34, 25, 18, 1, 37, 22 }; 

     int r1 = 0; 

     DateTime now = DateTime.Now; 
     for (int i = 0; i < 10000000; i++) // 10 mil iterations 1.5 - 2 sec 
     { r1 = TPTEvaluator.LookupHand(str);} // here 
     TimeSpan s1 = DateTime.Now - now; 
     textBox14.Text = "" + s1.TotalMilliseconds; 
    } 

मेरा मानना ​​है कि यह विधि मूल रूप से सी ++ में लागू की गई थी, लेकिन एन फिर भी सी # पोर्ट तेजी से काम करना चाहिए। क्या कोई तरीका है कि मैं एक सेकंड में कम से कम 100 लाख हाथों के करीब कैसे पहुंच सकता हूं?

क्या मैं अब तक की कोशिश की:

  • स्टेटिक उपयोग करने की कोशिश, और गैर स्थिर तरीकों - कोई फर्क नहीं।
  • शब्दकोश देखने के बजाय सरणी

    public void ArrToDict(int[] arr, Dictionary<int, int> dic) 
    { 
        for (int i = 0; i < arr.Length; i++) 
        { 
         dic.Add(i, arr[i]); 
        } 
    } 
    
    public unsafe static int LookupHandDict(int[] cards) 
    { 
        int p = dict[53 + cards[0]]; 
        p = dict[p + cards[1]]; 
        p = dict[p + cards[2]]; 
        p = dict[p + cards[3]]; 
        p = dict[p + cards[4]]; 
        p = dict[p + cards[5]]; 
        return dict[p + cards[6]]; 
    } 
    

बीता हुआ समय हाथ के 10 मिलों के लिए लगभग 6 बार धीमी ..

  • एक व्यक्ति के अनुसार उपयोग करने की कोशिश - वह वृद्धि हुई "असुरक्षित" कोड को हटाकर 200 मिलों द्वारा प्रदर्शन। मैंने एक ही काम करने की कोशिश की लेकिन परिणाम लगभग समान हैं।

    सी # संस्करण में "असुरक्षित" कोड भागों और कुछ छोटे समायोजन को हटाने के बाद यह अब भी चारों ओर 310 Mio है:

    public static int LookupHand(int[] cards) 
    { 
         int p = _lut[53 + cards[0]]; 
         p = _lut[p + cards[1]]; 
         p = _lut[p + cards[2]]; 
         p = _lut[p + cards[3]]; 
         p = _lut[p + cards[4]]; 
         p = _lut[p + cards[5]]; 
         return _lut[p + cards[6]]; 
    } 
    

यहाँ उद्धरण है।

इस हाथ रैंकिंग प्रणाली के प्रदर्शन को बढ़ाने के लिए किसी भी अन्य तरीका है?

+10

क्या आपने रिलीज़ मोड में चलाने का प्रयास किया है? यह तब तेज प्रदर्शन कर सकता है, क्योंकि कोड अनुकूलित किया गया है। –

+0

.dat फ़ाइल जिसमें इन सभी प्रविष्टियों को शामिल किया गया है, आकार में 130 एमबी है .. फिर भी 1-2 गीगा रैम वाले पी 4 पीसी में कोई समस्या नहीं थी। मेरे पास 4 गीगा हैं, इसलिए राम को एक समस्या नहीं होनी चाहिए। – Alex

+0

@ मिचलबी। यह अब 200 मिलीसेकंड है !! बहुत बहुत धन्यवाद। मैं इस मुद्दे को हटा नहीं पाऊंगा .. हो सकता है कि कुछ और सुधार किए जा सकें .. धन्यवाद, फिर से !! – Alex

उत्तर

4

पहला - बेंचमार्किंग हमेशा मुश्किल है। जो चीजें आपकी मशीन पर एक तरह से करती हैं वे हमेशा अन्य मशीनों पर समान तरीके से प्रदर्शन नहीं करती हैं और 'अंडर-द-कवर' पर बहुत कुछ चल रहा है जो डेटा को अमान्य कर सकता है (जैसे ओएस या हार्डवेयर द्वारा किए गए कैशिंग)।

ऐसा कहकर - मैंने केवल आपकी इनिट() विधि को देखा और उसने मुझे अपने सिर को खरोंच कर दिया। मुझे इसका पालन करना मुश्किल लगता है। 'असुरक्षित' का उपयोग करने के लिए अंगूठे का मेरा नियम इसका उपयोग नहीं करना है, जब तक कि मुझे बिल्कुल नहीं करना चाहिए। यह Init() विधि, मुझे लगता है, एक बार बुलाया जाता है, है ना? मैं बेंचमार्क यह करने का फैसला किया:

static void BenchmarkIt(string input, Action myFunc) 
{ 
    myWatch.Restart(); 
    myFunc(); 
    myWatch.Stop(); 

    Console.WriteLine(input, myWatch.ElapsedMilliseconds); 
} 

BenchmarkIt("Updated Init() Method: {0}", Init2); 
BenchmarkIt("Original Init() Method: {0}", Init1); 

कहाँ Init1() अपने मूल कोड और Init2() मेरी फिर से लिखा कोड है (मैं भी क्रम में कई बार निष्पक्षता की खातिर में फ़्लिप किया है) है। यहाँ मैं (मेरे मशीन पर) क्या मिलेगा है ...

अपडेट किया गया Init() विधि: 110

मूल Init() विधि: 159

यहाँ कोड मैं प्रयोग किया जाता है। कोई असुरक्षित कीवर्ड आवश्यक नहीं है।

public static void Init2() 
{ 
    if (!File.Exists(fileName)) { throw new Exception("Handranks.dat not found"); }    

    BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open));    

    try 
    { 
     _lut = new int[maxSize]; 
     var tempBuffer = reader.ReadBytes(maxSize * 4); 
     Buffer.BlockCopy(tempBuffer, 0, _lut, 0, maxSize * 4); 
    } 
    finally 
    { 
     reader.Close(); 
    } 
} 

मेरी राय में, यह कोड पढ़ने के लिए आसान है और यह तेजी से चल रहा है।

मैं जानता हूँ कि आप शायद() का प्रदर्शन LookupHand बारे में अधिक चिंतित हैं, लेकिन मैं किसी भी महत्वपूर्ण सुधार करने के लिए सक्षम नहीं था। मैंने कुछ अलग दृष्टिकोणों की कोशिश की लेकिन कुछ भी मदद नहीं की।

मैं 500 मिलीसेकंड में अपना कोड 100,000,000 बार चलाने में सक्षम था। मैं काफी बीफ़ी 64-बिट लैपटॉप पर चल रहा हूं - जो कि आप जिस गति की अपेक्षा कर रहे थे वह प्रतीत होता है। दूसरों की तरह कहा है - रिलीज मोड (ऑप्टिमाइज़ेशन सक्षम करने) में चल रहा प्रदर्शन पर एक बड़ा प्रभाव हो सकता है।

+0

Init2() मेरे लिए शून्य लोड करता है .. – Alex

+0

@Alex - मैं वास्तव में शर्मिंदा हूं .... मैंने अपना इच्छित कोड पोस्ट नहीं किया था। कृपया अद्यतन कोड आज़माएं! बेंचमार्क मान अभी भी मेरी मशीन पर जो देख रहे हैं। –

4

आप सामान्य गति चाहते हैं, मैं Brecware पर मूल्यांकनकर्ता उपयोग करने का सुझाव होगा: http://www.brecware.com/Software/software.html। स्टीव ब्रेचर का मूल्यांकनकर्ता रेडब्ल्यू मूल्यांकनकर्ता से तुलनात्मक रूप से मूल्यांकन करता है जो यादृच्छिक क्रम में होता है, और यह अधिक कॉम्पैक्ट है।

टिप्पणियों में उल्लेख के अनुसार, रेडब्ल्यू मूल्यांकनकर्ता इसकी गति के संदर्भ के इलाके पर निर्भर करता है। यदि आप लुकअप टेबल के समान क्रम में मूल्यांकन को पार नहीं कर रहे हैं, तो यह धीमा होने जा रहा है। यदि यह आपकी समस्या है तो तीन दृष्टिकोण हैं:

  1. अपने मूल्यांकन आदेश को टेबल से अधिक बारीकी से मेल करें।
  2. अपने मूल्यांकन आदेश से मेल खाने वाली टेबल बनाएं
  3. अपने उपयोग के मामले में एक मूल्यांकनकर्ता अनुकूलित करें।
+0

दुर्भाग्यवश कोई सी # पोर्ट नहीं है – Alex

संबंधित मुद्दे