Pregunta ¿Cuál es la diferencia entre los atributos atómicos y no atómicos?


Qué hacer atomic y nonatomic significa en declaraciones de propiedad?

@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

¿Cuál es la diferencia operativa entre estos tres?


1722
2018-02-26 02:31


origen


Respuestas:


Los dos últimos son idénticos; "atómico" es el comportamiento predeterminado (tenga en cuenta que no es en realidad una palabra clave; está especificado solo por la ausencia de nonatomic - atomic se agregó como palabra clave en las versiones recientes de llvm / clang).

Suponiendo que estás sintetizando las implementaciones del método, los cambios atómicos y no atómicos cambian el código. Si está escribiendo su propio setter / getters, atomic / nonatomic / retain / assign / copy son meramente asesores. (Nota: @synthesize es ahora el comportamiento predeterminado en las versiones recientes de LLVM. Tampoco es necesario declarar variables de instancia; también se sintetizarán automáticamente y tendrán un _ antepuesto a su nombre para evitar el acceso directo accidental).

Con "atómico", el setter / getter sintetizado asegurará que todo el valor siempre se devuelve desde el getter o el setter lo establece, independientemente de la actividad del setter en cualquier otro thread. Es decir, si el hilo A está en el medio del captador mientras el hilo B llama al colocador, un valor viable real, es decir, un objeto liberado automáticamente, se devolverá a la persona que llama en A.

En nonatomic, no se hacen tales garantías. Así, nonatomic es considerablemente más rápido que "atómico".

Lo que "atómico" hace no hacer es hacer cualquier garantía sobre la seguridad del hilo. Si el subproceso A llama al captador de forma simultánea con el subproceso B y C llamando al instalador con valores diferentes, el subproceso A puede obtener cualquiera de los tres valores devueltos, el anterior a que se invoque a cualquier ajustador o se pase cualquiera de los valores a los definidores en B y C. Del mismo modo, el objeto puede terminar con el valor de B o C, no hay forma de saberlo.

Garantizar la integridad de los datos, uno de los principales desafíos de la programación multiproceso, se logra por otros medios.

Agregando a esto:

atomicity de una sola propiedad tampoco puede garantizar la seguridad del hilo cuando están en juego múltiples propiedades dependientes.

Considerar:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

En este caso, el hilo A podría cambiar el nombre del objeto llamando setFirstName: y luego llamar setLastName:. Mientras tanto, el hilo B puede llamar fullName entre dos llamadas del hilo A y recibirá el nuevo nombre junto con el apellido anterior.

Para abordar esto, necesitas un modelo transaccional. Es decir. algún otro tipo de sincronización y / o exclusión que permite excluir el acceso a fullName mientras las propiedades dependientes se están actualizando.


1668
2018-02-26 06:40



Esto se explica en Apple documentación, pero a continuación hay algunos ejemplos de lo que realmente está sucediendo. Tenga en cuenta que no hay palabra clave "atómica", si no especifica "no atómica", la propiedad es atómica, pero especificar "atómico" explícitamente dará como resultado un error.

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

Ahora, la variante atómica es un poco más complicada:

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

Básicamente, la versión atómica tiene que cerrarse para garantizar la seguridad del hilo, y también está superando el recuento de ref en el objeto (y el recuento de liberación automática para equilibrarlo) de modo que el objeto está garantizado para la persona que llama, de lo contrario habrá es una condición de carrera potencial si otro hilo está configurando el valor, lo que hace que el recuento de ref se reduzca a 0.

En realidad, hay una gran cantidad de variantes diferentes de cómo funcionan estas cosas, dependiendo de si las propiedades son valores u objetos escalares, y cómo interactúan retención, copia, solo lectura, no atómica, etc. En general, los sintetizadores de propiedades solo saben cómo hacer lo "correcto" para todas las combinaciones.


342
2018-02-26 06:24



Atómico

  • es el comportamiento predeterminado
  • asegurará que el proceso actual sea completado por la CPU, antes de que otro proceso acceda a la variable
  • no es rápido, ya que garantiza que el proceso se complete por completo

No atómico

  • NO es el comportamiento predeterminado
  • más rápido (para código sintetizado, es decir, para variables creadas usando @property y @synthesize)
  • no seguro para subprocesos
  • puede provocar un comportamiento inesperado, cuando dos procesos diferentes acceden a la misma variable al mismo tiempo

148
2018-05-25 10:56



La mejor forma de entender la diferencia es usando el siguiente ejemplo.

Supongamos que hay una propiedad de cadena atómica llamada "nombre", y si llama [self setName:@"A"] del hilo A, llamada [self setName:@"B"] del hilo B, y llamada [self name] desde el hilo C, todas las operaciones en diferentes hilos se realizarán en serie, lo que significa que si un hilo está ejecutando un setter o un getter, entonces otros hilos esperarán.

Esto hace que la propiedad "nombre" de lectura / escritura sea segura, pero si otro hilo, D, llama [name release] al mismo tiempo, esta operación puede producir un bloqueo porque no hay una llamada setter / getter involucrada aquí. Lo que significa que un objeto es de lectura / escritura segura (ATOMIC), pero no es seguro para subprocesos, ya que otros subprocesos pueden enviar simultáneamente cualquier tipo de mensajes al objeto. El desarrollador debe garantizar la seguridad de subprocesos para dichos objetos.

Si la propiedad "nombre" no fuera atómica, todos los hilos en el ejemplo anterior - A, B, C y D se ejecutarán simultáneamente produciendo cualquier resultado impredecible. En el caso de atómica, cualquiera de A, B o C se ejecutará primero, pero D aún puede ejecutar en paralelo.


125
2018-01-31 18:36



La sintaxis y la semántica ya están bien definidas por otras excelentes respuestas a esta pregunta. Porque ejecución y actuación no se detallan bien, añadiré mi respuesta.

¿Cuál es la diferencia funcional entre estos 3?

Siempre había considerado atómico como un defecto bastante curioso. En el nivel de abstracción en el que trabajamos, el uso de propiedades atómicas para una clase como vehículo para lograr el 100% de seguridad de hilo es un caso de esquina. Para programas verdaderamente correctos de multiproceso, la intervención del programador es casi seguro un requisito. Mientras tanto, las características de rendimiento y la ejecución aún no se han detallado en profundidad. Después de haber escrito algunos programas muy multiproceso en los últimos años, había estado declarando mis propiedades como nonatomictodo el tiempo porque atómico no era sensato para ningún propósito. Durante la discusión de los detalles de las propiedades atómicas y no atómicas esta pregunta, Hice algunos perfiles encontré algunos resultados curiosos.

Ejecución

De acuerdo. Lo primero que me gustaría aclarar es que la implementación de bloqueo está definida y definida por la implementación. Louis usa @synchronized(self) en su ejemplo, he visto esto como una fuente común de confusión. La implementación no actualmente utilizar @synchronized(self); usa el nivel de objeto girar cerraduras. La ilustración de Louis es buena para una ilustración de alto nivel utilizando construcciones con las que todos estamos familiarizados, pero es importante saber que no usa @synchronized(self).

Otra diferencia es que las propiedades atómicas retendrán / liberarán el ciclo de sus objetos dentro del captador.

Actuación

Aquí está la parte interesante: rendimiento usando accesos de propiedades atómicas en incontestado (por ejemplo, los casos de un solo hilo) pueden ser realmente muy rápidos en algunos casos. En casos menos que ideales, el uso de accesos atómicos puede costar más de 20 veces la sobrecarga de nonatomic. Mientras que la Contestó el uso de 7 subprocesos fue 44 veces más lento para la estructura de tres bytes (2.2 GHz) Core i7 Quad Core, x86_64). La estructura de tres bytes es un ejemplo de una propiedad muy lenta.

Nota informativa interesante: los accesadores definidos por el usuario de la estructura de tres bytes eran 52 veces más rápidos que los accesadores atómicos sintetizados; o 84% de la velocidad de los accesadores no atómicos sintetizados.

Los objetos en casos impugnados también pueden exceder 50 veces.

Debido al número de optimizaciones y variaciones en las implementaciones, es bastante difícil medir los impactos del mundo real en estos contextos. A menudo puede escuchar algo como "Confía en él, a menos que hagas un perfil y descubras que es un problema". Debido al nivel de abstracción, en realidad es bastante difícil medir el impacto real. Recolectar los costos reales de los perfiles puede consumir mucho tiempo, y debido a las abstracciones, es bastante impreciso. Además, ARC vs MRC puede hacer una gran diferencia.

Así que retrocedamos, no centrándonos en la implementación de accesos a propiedades, incluiremos a los sospechosos habituales como objc_msgSend, y examine algunos resultados de alto nivel del mundo real para muchas llamadas a un NSString obtener en incontestado casos (valores en segundos):

  • MRC | no atómico | getters implementados manualmente: 2
  • MRC | no atómico | Gancho sintetizado: 7
  • MRC | atómico | captador sintetizado: 47
  • ARC | no atómico | captador sintetizado: 38 (nota: ARC está agregando recuento de ref aquí en bicicleta)
  • ARC | atómico | captador sintetizado: 47

Como probablemente haya adivinado, la actividad / ciclo de recuento de referencia es un contribuyente significativo con átomos y bajo ARC. También verías mayores diferencias en los casos impugnados.

Aunque presto mucha atención al rendimiento, todavía digo ¡Semántica primero!. Mientras tanto, el rendimiento es una baja prioridad para muchos proyectos. Sin embargo, conocer los detalles de ejecución y los costos de las tecnologías que usa ciertamente no hace daño. Debe usar la tecnología adecuada para sus necesidades, propósitos y capacidades. Con suerte, esto le ahorrará unas horas de comparaciones y le ayudará a tomar una decisión mejor informada al diseñar sus programas.


108
2017-08-18 09:47



Atómico= seguridad de hilo

No atómico = Sin hilos de seguridad

Seguridad del hilo:

Las variables de instancia son seguras para subprocesos si se comportan correctamente cuando se accede desde varios subprocesos, independientemente de la programación o el entrelazado de la ejecución de dichos subprocesos por el entorno de tiempo de ejecución, y sin sincronización adicional u otra coordinación por parte del código de llamada.

En nuestro contexto:

Si un hilo cambia el valor de la instancia, el valor modificado está disponible para todos los hilos, y solo un hilo puede cambiar el valor a la vez.

Dónde utilizar atomic:

si se va a acceder a la variable de instancia en un entorno multiproceso.

Implicación de atomic:

No tan rápido como nonatomic porque nonatomic no requiere ningún trabajo de vigilancia desde el tiempo de ejecución.

Dónde utilizar nonatomic:

Si la variable de instancia no va a cambiarse por varios hilos, puede usarla. Mejora el rendimiento.


89
2017-07-10 13:07



Encontré una explicación bastante buena de las propiedades atómicas y no atómicas aquí. Aquí hay un texto relevante de la misma:

'atómico' significa que no se puede descomponer.   En términos de OS / programación, una llamada a función atómica es una que no se puede interrumpir: toda la función debe ejecutarse y no intercambiarse fuera de la CPU por el cambio de contexto habitual del sistema operativo hasta que esté completa. En caso de que no lo supiera: dado que la CPU solo puede hacer una cosa a la vez, el sistema operativo rota el acceso a la CPU a todos los procesos en ejecución en pequeños intervalos de tiempo, para dar el espejismo de multitarea. El programador de la CPU puede (y lo hace) interrumpir un proceso en cualquier punto de su ejecución, incluso en una llamada de función intermedia. Por lo tanto, para acciones como actualizar variables de contador compartidas donde dos procesos podrían intentar actualizar la variable al mismo tiempo, deben ejecutarse 'atómicamente', es decir, cada acción de actualización debe finalizar en su totalidad antes de que cualquier otro proceso pueda intercambiarse en el UPC.

Así que supongo que atómico en este caso significa que los métodos de lectura de atributos no se pueden interrumpir, lo que significa que la (s) variable (s) que lee el método no pueden cambiar su valor a la mitad porque se obtiene algún otro subproceso / llamada / función. intercambiado en la CPU.

Porque el atomic las variables no pueden ser interrumpidas, el valor contenido por ellas en cualquier punto es (thread-lock) garantizado incorrupto, aunque, al garantizar este bloqueo de hilo, el acceso a ellos es más lento. non-atomic las variables, por otro lado, no ofrecen tal garantía pero ofrecen el lujo de un acceso más rápido. Para resumir, ve con non-atomic cuando sepas que tus variables no serán accedidas por múltiples hilos simultáneamente y acelerarán las cosas.


67
2018-02-24 05:17



Después de leer tantos artículos, apilar las publicaciones de Overflow y hacer aplicaciones de demostración para verificar los atributos de propiedad de las variables, decidí juntar toda la información de los atributos:

  1. atomic             // Defecto
  2. nonatomic
  3. strong = retain        // Defecto
  4. weak = unsafe_unretained
  5. retain
  6. assign             // Defecto
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite                 // Defecto

En el artículo Atributos o modificadores de propiedades variables en iOS puedes encontrar todos los atributos mencionados anteriormente y eso definitivamente te ayudará.

  1. atomic

    • atomic significa que solo un hilo accede a la variable (tipo estático).
    • atomic es seguro para subprocesos
    • Pero es lento en rendimiento
    • atomic es el comportamiento predeterminado
    • Los accesadores atómicos en un entorno no recogido de basura (es decir, al usar retener / liberar / liberar automáticamente) utilizarán un bloqueo para garantizar que otro subproceso no interfiera con la configuración / obtención correcta del valor.
    • En realidad no es una palabra clave.
       

    Ejemplo:

        @property (retain) NSString *name;
    
        @synthesize name;
    
  2. nonatomic

    • nonatomic significa acceso múltiple a la variable (tipo dinámico).
    • nonatomic es inseguro en el hilo.
    • Pero es rápido en rendimiento
    • nonatomic NO es un comportamiento predeterminado. Necesitamos agregar el nonatomic palabra clave en el atributo de propiedad.
    • Puede provocar un comportamiento inesperado, cuando dos procesos (hilos) diferentes acceden a la misma variable al mismo tiempo.
       

    Ejemplo:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;
    

61
2018-03-21 07:10



La respuesta más fácil primero: no hay diferencia entre los dos segundos ejemplos. Por defecto, los accesores de propiedad son atómicos.

Los accesadores atómicos en un entorno no recogido de basura (es decir, al usar retener / liberar / liberar automáticamente) utilizarán un bloqueo para garantizar que otro subproceso no interfiera con la configuración / obtención correcta del valor.

Ver el "Rendimiento y roscado"sección de la documentación de Objective-C 2.0 de Apple para obtener más información y otras consideraciones al crear aplicaciones de subprocesos múltiples.


52
2018-02-26 02:56



Atómico

Garantías atómicas de que el acceso a la propiedad se realizará de forma atómica. P.ej. siempre devuelve un objeto completamente inicializado, cualquier obtención / conjunto de una propiedad en un subproceso debe completarse antes de que otro pueda acceder a él.

Si imagina que la siguiente función se produce en dos hilos a la vez, puede ver por qué los resultados no serían bonitos.

-(void) setName:(NSString*)string
{
  if (name)
  {
    [name release]; 
    // what happens if the second thread jumps in now !?
    // name may be deleted, but our 'name' variable is still set!
    name = nil;
  }

  ...
}

Pros: El retorno de los objetos completamente inicializados cada vez lo convierte en la mejor opción en caso de multi-threading.

Contras : Rendimiento alcanzado, hace que la ejecución sea un poco más lenta

No atómico:

A diferencia de Atomic, no garantiza el retorno de objetos completamente inicializados cada vez.

Pros: Ejecución extremadamente rápida.

Contras : Posibilidades de valor de basura en caso de multi-threading.


52
2018-02-26 02:41



Atómico significa que solo un hilo accede a la variable (tipo estático). Atomic es seguro para subprocesos, pero es lento.

Nonatomic significa que múltiples hilos acceden a la variable (tipo dinámico). Nonatomic es inseguro, pero es rápido.


31
2017-11-22 11:20