2009-06-08 12 views
9

Al revisar el código, encontré varias nuevas variables privadas compartidas (de tipo Hashtables (Of String), inicializadas en la declaración) agregadas a una clase parcial para una clase muy grande (derivada de DataContext). Esto me parece sensato en un sentido porque nunca cambian, y hacer que estas variables compartidas aseguren que no se reiniciarán cada vez que se llame a una función. Sin embargo, estas variables son solo usadas dentro del alcance de una función en la clase, y me temo que el espacio de nombres privado de esta clase derivada de DataContext se está contaminando, y tener este tipo de cosas expuestas en un nivel tan alto podría ser Confundir a otros leyendo el código en el futuro. ¿Habría un impacto negativo en el rendimiento al hacer estas variables locales dentro de la función donde se usan, o hay alguna forma mejor de manejar esto? Básicamente estamos usando estas 3 tablas hash para determinar si algo dentro de subconjuntos particulares de propiedades cambió (usando GetModifiedMembers y luego usando la función Overlaps del hashset para ver si alguno de los miembros modificados corresponde a los miembros que nos interesan).Variables privadas compartidas frente a variables locales/espacio de nombres ¿Contaminación frente a rendimiento?

Edité: Me derrumbé y me tomé el tiempo para escribir mi propio programa de prueba, que confirmó que hay un costo para usar variables locales (que supongo se aplica generalmente a todos los casos - dudo que haya un caso variable sería más lenta a menos que use la variable compartida requiere un poco de lógica adicional para hacerlo correctamente): salida

Sub Main() 
    Dim st As New Stopwatch() 
    Dim specialCount As Integer = 0 
    Dim r As New Random() 
    Dim params As Integer() 
    ReDim params(0 To 9) 
    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialShare(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Shared: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

    st.Reset() 
    specialCount = 0 

    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialLocal(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Local: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

End Sub 

Dim specialListShared As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 

Private Function IsSpecialLocal(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Dim specialListLocal As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 
    Return specialListLocal.Overlaps(paramList) 
End Function 

Private Function IsSpecialShare(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Return specialListShared.Overlaps(paramList) 
End Function 

muestra:

Shared: 75232 
00:00:00.0408223 
Local: 75018 
00:00:00.1344628 

así que en este caso particular, el uso de la variable local cuesta alrededor de 200% . Pero en la mayoría de los casos (incluido el mío), el tiempo es probablemente insignificante en comparación con la tarea general. Así que supongo que la pregunta ahora es: ¿cómo se siente la gente en general sobre la mejora de la capacidad de mantenimiento de los códigos a costa de impactos de rendimiento insignificantes pero conocidos?

Respuesta

6

Yo diría que necesita determinar si esas variables estáticas realmente pertenecen al espacio de nombres, clase o función. Si realmente son específicos de la función, los pondré dentro de la función.

Si necesita variables que conserven el estado incluso después de que la función salga del ámbito, puede declararlas como Static. Eso descarta el problema de tener estas variables en el alcance de la clase.

diferencia entre la variable compartida clase, variable de función estática, y la variable de función local:

compartido: No será sólo una copia de la variable entre todas las instancias de clase.

Estático: Habrá una copia de la variable por instancia de su clase.

Local: Se creará una copia de la variable cada vez que se llame a la función (pero se liberará cuando la función se salga del alcance).

Utilice el que tenga sentido en su situación.

+0

No creo que me preocupe el rendimiento real medible aquí, ya que la diferencia probablemente sería indetectablemente pequeña. Y existen directrices basadas en el rendimiento, independientemente de la necesidad de crear perfiles de casos individuales. Eso es lo que busco aquí. Por ejemplo, generalmente debe usar variables de tipo fuerte en lugar de referencias a objetos para tratar con tipos de valores cuando sea posible debido al costo del boxeo y el desembalaje. Mi pregunta, en líneas similares, es si hay un costo apreciable a considerar cuando se usan variables locales en lugar de variables compartidas. Beneficio/Costo? – BlueMonkMN

+0

En realidad es una constante, pero (aunque VB.NET permite constantes locales) no es posible declarar una constante con este tipo de valor, por lo que debemos declarar una variable. Y luego nos encontramos con una pregunta similar: es el costo de la sobrecarga de tener las instancias adicionales que valen la pena el beneficio de no contaminar el espacio de nombres de la clase. Realmente es una constante aplicable solo a esa función específica. Es solo una lista de nombres de propiedad para propiedades cuyos valores se manejan dentro de esa función. – BlueMonkMN

+0

Entonces lo declararía como una variable local estática. La sobrecarga es probablemente muy pequeña, por lo que vale la pena no contaminar el espacio de nombres de la clase, a menos que haya millones de objetos de ese tipo que se creen. (1 millón de objetos = 1 millón de copias de su variable estática) –

0

Cuando dice "compartido" - ¿ese es VB-speak para static? Si es así, tenga en cuenta que podría estar en peligro de enhebrar si no tiene cuidado ... y dada la descripción, parece que esta información puede ser mutable. Podría ser ... "interesante" si alguna vez tienes varias instancias/hilos.

Tal vez estoy siendo demasiado paranoico - difícil de decir, no hay código ilustrativo ...

campos de instancia (en lugar de campos compartidos/estáticas) sería mi suposición por defecto - pero de nuevo, sin contexto no puedo estar 100% seguro.

+0

Sí, VB.Net Compartido = C# Estático – Pondidum

+3

o == ¿debería decirlo? – Pondidum

+0

No deberían cambiar. Ver mi comentario "Esto me parece sensato en un sentido porque nunca cambian". – BlueMonkMN

0

Casi olvidé que VB.NET admite variables locales estáticas. La siguiente prueba indica que puedo obtener un rendimiento tan bueno mediante el uso de una variable local estática:

Sub Main() 
    Dim st As New Stopwatch() 
    Dim specialCount As Integer = 0 
    Dim r As New Random() 
    Dim params As Integer() 
    ReDim params(0 To 9) 
    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialShare(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Shared: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

    st.Reset() 
    specialCount = 0 

    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialLocal(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Local: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

    st.Reset() 
    specialCount = 0 

    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialStatic(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Static: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

End Sub 

Dim specialListShared As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 

Private Function IsSpecialLocal(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Dim specialListLocal As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 
    Return specialListLocal.Overlaps(paramList) 
End Function 

Private Function IsSpecialShare(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Return specialListShared.Overlaps(paramList) 
End Function 

Private Function IsSpecialStatic(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Static specialListLocal As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 
    Return specialListLocal.Overlaps(paramList) 
End Function 

Salida de ejemplo:

Shared: 74836 
00:00:00.0498081 
Local: 75205 
00:00:00.1317149 
Static: 74862 
00:00:00.0469154 

Por cierto, siempre me he preguntado si C# soporta variables locales estáticas, ¿Y si no, Pórque no? Hay algunas características molestas que faltan en C# que VB.NET admite.

+0

Esto no es bueno. Las variables estáticas de las funciones no compartidas asignan almacenamiento en cada instancia, que es (en nuestra situación) el peor costo de todos. Supongo que podríamos crear otra función compartida que haga el trabajo con las variables estáticas, pero esa función aún sería "contaminación del espacio de nombres". Supongo que tendremos que quedarnos con el campo de clase compartido por ahora. – BlueMonkMN

Cuestiones relacionadas