2012-05-07 25 views
19

Tôi đang cố gắng sử dụng phương pháp "Trình đánh giá tay RayW" để có điểm kết hợp thẻ (5 thẻ tốt nhất trong số 7 thẻ). Tuy nhiên, tôi có một số vấn đề về hiệu suất với phương pháp này. Theo các nguồn tin - sử dụng cách tiếp cận này, nó phải có khả năng đánh giá hơn 300 triệu tay mỗi giây! Kết quả của tôi là 10 nhà máy trong 1,5 giây, chậm hơn nhiều lần.Đánh giá tay poker nhanh hơn

Ý tưởng đằng sau "RayW tay đánh giá" là như sau:

Hai cộng với hai đánh giá bao gồm một bảng tra cứu lớn chứa một số 32.000.000 mục (32.487.834 để được chính xác). Theo thứ tự để tra cứu một lá bài xì phé 7 lá bài đã cho, bạn theo dõi một lối đi qua bảng này, thực hiện một lần tra cứu trên mỗi thẻ. Khi bạn nhận được vào thẻ cuối cùng, giá trị để thu được là giá trị tương đương chính thức của Mặt

đây là cách mã trông giống như:

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]]; 
     } 
    } 
} 

}

và đó là cách tôi thử nghiệm phương pháp này:

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; 
    } 

Tôi tin rằng phương pháp này ban đầu được triển khai trong C++, nhưng n tuy nhiên C# port sẽ hoạt động nhanh hơn. Có cách nào để tôi có thể đến gần ít nhất 100 triệu tay trong một giây không?

gì tôi đã cố gắng cho đến nay:

  • cố gắng sử dụng tĩnh, và các phương pháp không tĩnh - không có sự khác biệt.
  • cố gắng sử dụng tra cứu từ điển thay vì mảng

    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]]; 
    } 
    

Thời gian đã qua 10 nhà máy của bàn tay là gần 6 chậm hơn lần ..

  • Theo một người - anh nâng tỷ số hiệu suất của 200 nhà máy bằng cách xóa mã "không an toàn". Tôi đã cố gắng làm điều tương tự nhưng kết quả gần như giống nhau.

    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]]; 
    } 
    

Dưới đây là đoạn trích:

Sau khi loại bỏ những phần mã "không an toàn" và một số điều chỉnh nhỏ trong cáC# phiên bản c nó bây giờ cũng khoảng 310 mio là.

có cách nào khác để tăng hiệu suất của hệ thống xếp hạng tay này không?

+10

Bạn đã thử chạy trong chế độ phát hành chưa? Nó có thể hoạt động nhanh hơn sau đó, bởi vì mã được tối ưu hóa. –

+0

tệp .dat chứa tất cả các mục này có kích thước 130 Mb. Tuy nhiên, P4 PC có 1-2 gigs ram không có bất kỳ vấn đề gì. Tôi có 4 hợp đồng biểu diễn, vì vậy RAM không phải là vấn đề lớn. – Alex

+0

@MichalB. bây giờ là 200 mili giây !! Cảm ơn nhiều. Tôi sẽ không loại bỏ vấn đề này .. có thể có một số cải tiến khác có thể được thực hiện .. Cảm ơn bạn, một lần nữa !! – Alex

Trả lời

4

Điểm chuẩn đầu tiên luôn khó khăn. Những thứ thực hiện một cách trên máy của bạn không phải lúc nào cũng thực hiện theo cùng một cách trên các máy khác và có rất nhiều thứ đang diễn ra có thể làm mất hiệu lực dữ liệu (như bộ nhớ đệm được thực hiện bởi hệ điều hành hoặc thậm chí phần cứng).

Có nói rằng - Tôi chỉ xem xét phương thức Init() của bạn và nó khiến tôi gãi đầu. Tôi thấy khó theo dõi. Quy tắc chung của tôi về việc sử dụng 'không an toàn' là không sử dụng nó, trừ khi tôi hoàn toàn phải làm vậy. Phương thức Init() này, tôi giả sử, được gọi một lần, đúng không? Tôi quyết định điểm chuẩn nó:

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); 

đâu Init1() là mã ban đầu của bạn và Init2() là mã viết lại của tôi (Tôi cũng đã lật trật tự nhiều lần trong lợi ích của sự công bằng). Đây là những gì tôi nhận được (trên máy tính của tôi) ...

Cập nhật Init() Phương pháp: 110

gốc Init() Phương pháp: 159

Dưới đây là đoạn code tôi sử dụng. Không yêu cầu từ khóa không an toàn.

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(); 
    } 
} 

Theo tôi, mã này dễ đọc hơn và dường như chạy nhanh hơn.

Tôi biết bạn có thể quan tâm nhiều hơn đến hiệu suất của LookupHand(), nhưng tôi không thể thực hiện bất kỳ cải tiến đáng kể nào. Tôi đã thử một vài cách tiếp cận khác nhau nhưng không có gì hữu ích.

Tôi đã có thể chạy mã của bạn 100.000.000 lần trong 500 mili giây. Tôi đang chạy trên một máy tính xách tay 64-bit khá beefy - mà dường như là tốc độ bạn mong đợi. Giống như những người khác đã nói - chạy trong chế độ phát hành (cho phép tối ưu hóa) có thể có tác động lớn đến hiệu suất.

+0

Init2() tải số không cho tôi .. – Alex

+0

@ Alex - Tôi thực sự xấu hổ .... Tôi đã không đăng mã tôi đã dự định. Vui lòng thử mã cập nhật ngay bây giờ! Các giá trị chuẩn vẫn là những gì tôi thấy trên máy tính của mình. –

4

Nếu bạn muốn tốc độ chung, tôi khuyên bạn nên sử dụng bộ đánh giá tại Brecware: http://www.brecware.com/Software/software.html. Bộ đánh giá của Steve Brecher nhanh hơn bộ đánh giá RayW để đánh giá diễn ra theo thứ tự ngẫu nhiên và nhỏ gọn hơn nhiều.

Như đã lưu ý trong nhận xét, bộ đánh giá RayW phụ thuộc vào địa phương tham chiếu cho tốc độ của nó. Nếu bạn không vượt qua các đánh giá theo thứ tự chính xác như các bảng tra cứu, nó sẽ chậm. Nếu đó là vấn đề của bạn, có ba cách tiếp cận:

  1. Làm cho thứ tự đánh giá của bạn phù hợp hơn với bảng.
  2. Làm cho bảng phù hợp với thứ tự đánh giá của bạn
  3. Làm cho trình đánh giá được tối ưu hóa cho trường hợp sử dụng của bạn.
+0

tiếc là không có cổng C# – Alex