c# - reparten - Evaluación más rápida de la mano de poker
poker jugadas (2)
En primer lugar, el benchmarking siempre es complicado. Las cosas que funcionan de una manera en su máquina no siempre funcionan de la misma manera en otras máquinas y hay muchas cosas "ocultas" que pueden invalidar los datos (como el almacenamiento en caché realizado por el sistema operativo o incluso el hardware).
Habiendo dicho eso, eché un vistazo al método Init () y me dejó rascándome la cabeza. Me resultó difícil de seguir. Mi regla de oro para usar ''no seguro'' es no usarlo, a menos que sea absolutamente necesario. Este método Init (), supongo, se llama una vez, ¿verdad? Decidí compararlo
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);
Donde Init1 () es su código original e Init2 () es mi código reescrito (también he cambiado el orden varias veces en aras de la imparcialidad). Esto es lo que obtengo (en mi máquina) ...
Método Init () actualizado: 110
Método original de Init (): 159
Aquí está el código que utilicé. No se requieren palabras clave inseguras.
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();
}
}
En mi opinión, este código es más fácil de leer y parece funcionar más rápido.
Sé que probablemente esté más preocupado por el rendimiento de LookupHand (), pero no pude realizar ninguna mejora significativa. Intenté algunos enfoques diferentes, pero nada que ayudó.
Pude ejecutar su código 100,000,000 veces en 500 milisegundos. Estoy ejecutando en una laptop de 64 bits bastante robusta, que parece ser la velocidad que esperabas. Como han dicho otros, ejecutar en modo de lanzamiento (habilitar la optimización) puede tener un gran impacto en el rendimiento.
Estoy tratando de usar el enfoque del "evaluador de manos RayW" para obtener una puntuación de combinación de cartas (5 mejores cartas de 7). Sin embargo, estoy teniendo algunos problemas de rendimiento con este método. Según las fuentes, utilizando este enfoque debe ser posible evaluar más de 300 mil manos por segundo. Mi resultado es 10 mills en 1.5 segundos, lo cual es muchas veces más lento.
La idea detrás de "evaluador de mano RayW" es la siguiente:
El evaluador Two Plus Two consiste en una gran tabla de búsqueda que contiene unos treinta y dos millones de entradas (32,487,834 para ser precisos). Para buscar una mano de póker de 7 cartas dada, traza un camino a través de esta tabla, realizando una búsqueda por carta. Cuando llegas a la última carta, el valor así obtenido es el valor oficial de equivalencia de la mano.
Aquí es cómo se ve el código:
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]];
}
}
}
}
Y así es como pruebo este enfoque:
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;
}
Creo que este método se implementó originalmente en C ++, pero sin embargo, el puerto C # debería funcionar más rápido. ¿Hay alguna manera de poder acercarme a al menos 100 millones de manos en un segundo?
Lo que intenté hasta ahora:
- Intenté usar métodos estáticos y no estáticos, sin diferencias.
Intenté usar la búsqueda del diccionario en lugar de la matriz
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]]; }
El tiempo transcurrido para 10 millones de manos es casi 6 veces más lento.
Según una persona, aumentó el rendimiento en 200 mills al eliminar el código "inseguro". Intenté hacer lo mismo pero los resultados son casi los mismos.
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]]; }
Aquí está la cita:
Después de eliminar las partes de código "inseguras" y algunos pequeños ajustes en la versión de c # ahora también está alrededor de 310 mio.
¿Hay alguna otra manera de aumentar el rendimiento de este sistema de clasificación manual?
Si desea una velocidad genérica, sugeriría usar el evaluador en Brecware: http://www.brecware.com/Software/software.html . El evaluador de Steve Brecher es más rápido que el evaluador de RayW para evaluaciones que ocurren en orden aleatorio, y es mucho más compacto.
Como se señaló en los comentarios, el evaluador de RayW depende de la localidad de referencia para su velocidad. Si no está atravesando las evaluaciones exactamente en el mismo orden que las tablas de búsqueda, será lento. Si ese es tu problema hay tres enfoques:
- Haga que su orden de evaluación coincida más estrechamente con las tablas.
- Haz tablas que coincidan con tu orden de evaluación
- Haz un evaluador optimizado para tu caso de uso.