pasar por in
referencia parece lógicamente equivalente a pasar por valor.
Correcto.
¿Existe algún tipo de ventaja en el rendimiento?
Si.
Yo creía que en el lado del back-end de las cosas, un ref
parámetro debe al menos copiar la dirección física de la variable, que debe ser del mismo tamaño que cualquier referencia de objeto típica.
No existe el requisito de que una referencia a un objeto y una referencia a una variable sean del mismo tamaño, y no existe el requisito de que ninguna sea del tamaño de una palabra de máquina, pero sí, en la práctica ambas son de 32 bits en 32 máquinas de bits y 64 bits en máquinas de 64 bits.
No tengo claro qué crees que tiene que ver la "dirección física" con esto. En Windows usamos direcciones virtuales , no direcciones físicas en el código de modo de usuario. Tengo curiosidad por saber en qué posibles circunstancias imagina que una dirección física es significativa en un programa de C #.
Tampoco es un requisito que se implemente una referencia de ningún tipo como la dirección virtual del almacenamiento. Las referencias pueden ser identificadores opacos en tablas GC en una implementación conforme a la especificación CLI.
¿La ventaja es solo en estructuras más grandes?
Disminuir el costo de pasar estructuras más grandes es el escenario motivador para la función.
Tenga en cuenta que no hay garantía de que in
un programa sea realmente más rápido y puede hacer que los programas sean más lentos. Todas las preguntas sobre desempeño deben ser respondidas mediante investigación empírica . Hay muy pocas optimizaciones que siempre sean ganadoras ; esta no es una optimización de "siempre ganar".
¿Hay alguna optimización del compilador detrás de escena que lo haga atractivo en otros lugares?
El compilador y el tiempo de ejecución pueden realizar cualquier optimización que elijan si hacerlo no infringe las reglas de la especificación C #. Que yo sepa, todavía no existe tal optimización para los in
parámetros, pero eso no excluye tales optimizaciones en el futuro.
¿Por qué no debería hacer que todos los parámetros estén incluidos?
Bueno, suponga que crea un int
parámetro en lugar de un in int
parámetro. ¿Qué costos se imponen?
- el sitio de la llamada ahora requiere una variable en lugar de un valor
- la variable no se puede registrar. El esquema de asignación de registros cuidadosamente ajustado del jitter acaba de recibir una llave inglesa.
- el código en el sitio de la llamada es más grande porque debe tomar una referencia a la variable y ponerla en la pila, mientras que antes simplemente podía empujar el valor a la pila de llamadas
- un código más grande significa que algunas instrucciones de salto corto pueden haberse convertido ahora en instrucciones de salto largo, por lo que, nuevamente, el código ahora es más grande. Esto tiene efectos colaterales en todo tipo de cosas. Los cachés se llenan antes, el jitter tiene más trabajo que hacer, el jitter puede optar por no realizar ciertas optimizaciones en códigos de mayor tamaño, etc.
- en el sitio del destinatario, hemos convertido el acceso a un valor en la pila (o registro) en una indirección en un puntero. Ahora, es muy probable que ese puntero esté en la caché, pero aún así, ahora hemos convertido un acceso de una instrucción al valor en un acceso de dos instrucciones.
- Y así.
Suponga que es un double
y lo cambia a un in double
. Nuevamente, ahora la variable no se puede registrar en un registro de punto flotante de alto rendimiento. Esto no solo tiene implicaciones en el rendimiento , ¡también puede cambiar el comportamiento del programa! A C # se le permite hacer aritmética flotante con una precisión superior a 64 bits y, por lo general, solo lo hace si los flotantes se pueden registrar.
Esta no es una optimización gratuita. Tienes que medir su desempeño contra las alternativas. Su mejor opción es simplemente no hacer estructuras grandes en primer lugar, como sugieren las pautas de diseño.
ref
se utiliza para pasar estructuras por referencia en lugar de copiarlas.in
significa que la estructura no debe modificarse.