Internado de cuerdas in.Net Marco-Cuáles son los beneficios y cuándo utilizar la pasantía


Quiero conocer el proceso y los aspectos internos de string interning específicos de.Net framework. También nos gustaría conocer los beneficios de usar interning y los escenarios/situaciones en los que deberíamos usar string interning para mejorar el rendimiento. Aunque he estudiado pasantía del libro CLR de Jeffery Richter, todavía estoy confundido y me gustaría saberlo con más detalle.

[Editar] para hacer una pregunta específica con un código de ejemplo como se muestra a continuación:

private void MethodA()
{
    string s = "String"; // line 1 - interned literal as explained in the answer        

    //s.intern(); // line 2 - what would happen in line 3 if we uncomment this line, will it make any difference?
}

private bool MethodB(string compareThis)
{
    if (compareThis == "String") // line 3 - will this line use interning (with and without uncommenting line 2 above)?
    {
        return true;
    }
    return false;
}
Author: VS1, 2011-11-08

5 answers

Interning es un detalle de implementación interna . A diferencia del boxeo , no creo que haya ningún beneficio en saber más de lo que has leído en el libro de Richter.

Los beneficios de micro-optimización de interning de cadenas manualmente son mínimos por lo tanto, generalmente no se recomienda.

Esto probablemente lo describe:

class Program
{
    const string SomeString = "Some String"; // gets interned

    static void Main(string[] args)
    {
        var s1 = SomeString; // use interned string
        var s2 = SomeString; // use interned string
        var s = "String";
        var s3 = "Some " + s; // no interning 

        Console.WriteLine(s1 == s2); // uses interning comparison
        Console.WriteLine(s1 == s3); // do NOT use interning comparison
    }
}
 17
Author: Aliostad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-04 12:34:43

En general, interning es algo que simplemente sucede, automáticamente, cuando se utilizan valores de cadena literales. La pasantía proporciona el beneficio de tener solo una copia del literal en la memoria, sin importar la frecuencia con que se use.

Dicho esto, es raro que haya una razón para internar sus propias cadenas que se generan en tiempo de ejecución, o incluso pensar en internar cadenas para un desarrollo normal.

Hay potencialmente algunos beneficios si vas a hacer mucho trabajo con comparaciones de cadenas generadas en tiempo de ejecución potencialmente idénticas (como interning puede acelerar las comparaciones a través de ReferenceEquals). Sin embargo, este es un uso altamente especializado, y requeriría una buena cantidad de perfiles y pruebas, y no sería una optimización que consideraría a menos que hubiera un problema medido en su lugar.

 26
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-08 17:23:15

Esta es una pregunta "vieja", pero tengo un ángulo diferente al respecto.

Si vas a tener un montón de cadenas de larga duración de un pequeño pool, interning puede mejorar la eficiencia de la memoria.

En mi caso, estaba internando otro tipo de objeto en un diccionario estático porque se reutilizaron con frecuencia, y esto sirvió como una caché rápida antes de persistirlos en el disco.

La mayoría de los campos en estos objetos son cadenas, y el conjunto de valores es bastante pequeño (mucho menor que el número de instancias, de todos modos).

Si estos fueran objetos transitorios, no importaría porque los campos de cadena serían basura recolectada a menudo. Pero debido a que se mantenían referencias a ellos, su uso de memoria comenzó a acumularse (incluso cuando no se agregaban nuevos valores únicos).

Así que internar los objetos redujo el uso de memoria sustancialmente, al igual que internar sus valores de cadena mientras estaban siendo internados.

 17
Author: harpo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-13 06:25:32

La internalización de cadenas afecta el consumo de memoria.

Por ejemplo, si lee cadenas y las mantiene en una lista para el almacenamiento en caché; y la misma cadena exacta ocurre 10 veces, la cadena se almacena realmente solo una vez en la memoria if cadena.Interno se utiliza. Si no, la cadena se almacena 10 veces.

En el siguiente ejemplo, la cadena.La variante interna consume alrededor de 44 MB y la versión sin (no comentada) consume 1195 MB.

static void Main(string[] args)
{
    var list = new List<string>();

    for (int i = 0; i < 5 * 1000 * 1000; i++)
    {
        var s = ReadFromDb();
        list.Add(string.Intern(s));
        //list.Add(s);
    }

    Console.WriteLine(Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024 + " MB");
}

private static string ReadFromDb()
{
    return "abcdefghijklmnopqrstuvyxz0123456789abcdefghijklmnopqrstuvyxz0123456789abcdefghijklmnopqrstuvyxz0123456789" + 1;
}

La internalización también mejora el rendimiento para iguales-comparar. El ejemplo a continuación la versión interna toma aproximadamente 1 unidades de tiempo, mientras que la no interna toma 7 unidades de tiempo.

static void Main(string[] args)
{
    var a = string.Intern(ReadFromDb());
    var b = string.Intern(ReadFromDb());
    //var a = ReadFromDb();
    //var b = ReadFromDb();

    int equals = 0;
    var stopwatch = Stopwatch.StartNew();
    for (int i = 0; i < 250 * 1000 * 1000; i++)
    {
        if (a == b) equals++;
    }
    stopwatch.Stop();

    Console.WriteLine(stopwatch.Elapsed + ", equals: " + equals);
}
 7
Author: J. Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-02 20:21:00

Las cadenas internadas tienen las siguientes características:

  • Dos cadenas internas que son idénticas tendrán la misma dirección en memoria.
  • La memoria ocupada por cadenas internadas no se libera hasta que su aplicación termina.
  • Internar una cadena implica calcular un hash y buscarlo en un diccionario que consume ciclos de CPU.
  • Si varios hilos internan cadenas al mismo tiempo, se bloquearán entre sí porque acceden al diccionario de las cadenas interned son serializadas.

Las consecuencias de estas características son:

  • Puede probar dos cadenas internadas para la igualdad simplemente comparando el puntero de dirección que es mucho más rápido que comparar cada carácter en la cadena. Esto es especialmente cierto si las cadenas son muy largas y comienzan con los mismos caracteres. Puede comparar cadenas internadas con el método Object.ReferenceEquals, pero es más seguro usar el operador string == porque comprueba si las cadenas es Internet primero.

  • Si usa la misma cadena muchas veces en su aplicación, la aplicación solo almacenará una copia de la cadena en la memoria, reduciendo la memoria necesaria para ejecutar su aplicación.

  • Si internas muchas cadenas diferentes, esto asignará memoria para aquellas cadenas que nunca se liberarán, y tu aplicación consumirá cantidades cada vez mayores de memoria.

  • Si tiene un número muy grande de cadenas internadas, string la internación puede volverse lenta, y los hilos se bloquearán entre sí al acceder al diccionario de cadenas internadas.

Debe usar interning de cadenas solo si:

  1. El conjunto de cadenas que está internando es bastante pequeño.
  2. Comparas estas cadenas muchas veces por cada vez que las internas.
  3. Realmente te importan las optimizaciones de rendimiento por minuto.
  4. No tienes muchos hilos que entrenen agresivamente cadenas.
 3
Author: bikeman868,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-26 01:11:03