una - herencia de constructores c#
En.Net, ¿cuándo debo pasar las estructuras por referencia por motivos de rendimiento? (5)
En mi aplicación C #, tengo una estructura grande (176 bytes) que se transfiere potencialmente cien mil veces por segundo a una función. Esta función simplemente toma un puntero a la estructura y pasa el puntero a un código no administrado. Ni la función ni el código no administrado harán modificaciones a la estructura.
Mi pregunta es, ¿debería pasar la estructura a la función por valor o por referencia? En este caso particular, mi suposición es que pasar por referencia sería mucho más rápido que insertar 176 bytes en la pila de llamadas, a menos que el JIT reconozca que la estructura nunca se modifica (mi suposición es que no puede reconocer esto porque la estructura la dirección se pasa al código no administrado) y optimiza el código.
Ya que estamos en ello, respondamos también al caso más general en el que la función no pasa el puntero de la estructura a un código no administrado, sino que realiza una operación de solo lectura en los contenidos de la estructura. ¿Sería más rápido pasar la estructura por referencia? En este caso, ¿el JIT reconocería que la estructura nunca se modifica y, por lo tanto, se optimiza? Presumiblemente, no es más eficiente pasar una estructura de 1 byte por referencia, pero ¿a qué tamaño de estructura se vuelve mejor pasar una estructura por referencia, si es que alguna vez?
Gracias.
EDITAR:
Como se señala a continuación, también es posible crear una clase "equivalente" para uso regular, y luego usar una estructura al pasar al código no administrado. Veo dos opciones aquí:
1) Cree una clase "envoltorio" que simplemente contenga la estructura, y luego fije y pase un puntero a la estructura al código no administrado cuando sea necesario. Un posible problema que veo es que pinning tiene sus propias consecuencias en el rendimiento.
2) Cree una clase equivalente cuyos campos se copian en la estructura cuando se necesita la estructura. Pero la copia tomaría mucho tiempo y me parece que para derrotar el punto de pasar por referencia en primer lugar.
EDITAR:
Como mencioné un par de veces a continuación, ciertamente podría medir el rendimiento de cada uno de estos métodos. Haré esto y publicaré los resultados. Sin embargo, todavía estoy interesado en ver las respuestas y los razonamientos de las personas desde una perspectiva intelectual.
Antes de preguntar si debe o no pasar la estructura por referencia, debe preguntarse por qué tiene una estructura tan enorme en primer lugar. ¿ Realmente necesita ser una estructura? Si necesita usar una estructura en algún punto para P / Invoke, ¿valdría la pena tener una estructura solo para eso, y luego la clase equivalente en otro lugar?
Una estructura tan grande es muy, muy inusual ...
Consulte la sección Pautas de diseño para desarrollar bibliotecas de clases sobre Elección entre clases y estructuras para obtener más orientación sobre esto.
La única forma en que puede obtener una respuesta a esta pregunta es codificar ambas y medir el rendimiento.
Menciona la interoperabilidad no administrada / administrada. Mi experiencia es que toma un tiempo sorprendentemente largo para la interoperabilidad. Puedes intentar cambiar tu código de:
void ManagedMethod(MyStruct[] items) {
foreach (var item in items) {
unmanagedHandle.ProcessOne(item);
}
}
A:
void ManagedMethod(MyStruct[] items) {
unmanagedHandle.ProcessMany(items, items.Count);
}
Esta técnica me ayudó en un caso similar, pero solo las mediciones le dirán si funciona para su caso.
¿No es esto algo que un compilador decente debería optimizar automáticamente, siempre que el callee no modifique la estructura?
Hice algunos perfiles muy informales, y los resultados indican que, para mi aplicación particular, hay una pequeña ganancia de rendimiento para pasar por referencia. Por valor-valor recibí alrededor de 10,050,000 llamadas por segundo, mientras que por referencia obtuve alrededor de 11,200,000 llamadas por segundo.
Su experiencia puede ser diferente.
¿Por qué no usar una clase en su lugar y pasar su clase a su función P / Invocar?
Usar la clase pasará muy bien en tu código administrado, y funcionará igual que pasar una estructura por referencia a una función P / Invocar.
p.ej
// What you have
public struct X
{
public int data;
}
[DllImport("mylib.dll")]
static extern void Foo( ref X arg);
// What you could do
[StructLayout(LayoutKind.Sequential)]
public class Y
{
public int data;
}
[DllImport("mylib.dll")]
static extern void Bar( Y arg );