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




objective-c properties (18)

atómico (por defecto)

Atomic es el valor predeterminado: si no escribe nada, su propiedad es atómica. Se garantiza una propiedad atómica que si intenta leer de ella, obtendrá un valor válido. No ofrece ninguna garantía sobre cuál podría ser ese valor, pero obtendrá buenos datos, no solo memoria basura. Lo que esto le permite hacer es si tiene varios subprocesos o múltiples procesos que apuntan a una sola variable, un subproceso puede leer y otro puede escribir. Si golpean al mismo tiempo, se garantiza que el hilo del lector obtendrá uno de los dos valores: antes del cambio o después del cambio. Lo que el atómico no le ofrece es cualquier tipo de garantía sobre cuál de esos valores podría obtener. Atomic es realmente confundido con ser seguro para subprocesos, y eso no es correcto. Necesitas garantizar la seguridad de tu hilo de otras maneras. Sin embargo, atomic garantizará que si intenta leer, recupere algún tipo de valor.

no atómico

Por otro lado, no atómico, como probablemente puedas adivinar, simplemente significa "no hagas esas cosas atómicas". Lo que pierdes es la garantía de que siempre recibes algo. Si intenta leer en medio de una escritura, podría recuperar datos de basura. Pero, por otro lado, vas un poco más rápido. Debido a que las propiedades atómicas tienen que hacer algo de magia para garantizar que recuperas un valor, son un poco más lentas. Si se trata de una propiedad a la que está accediendo mucho, es posible que desee desplegar a nonatomic para asegurarse de que no está incurriendo en esa penalización de velocidad.

Vea más aquí: https://realm.io/news/tmi-objective-c-property-attributes/

¿Qué significa atomic y no atomic en las 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?


Atómico

Atomic garantiza que el acceso a la propiedad se realizará de manera atómica. Por ejemplo, siempre devuelve un objeto completamente inicializado, cualquier obtención / conjunto de una propiedad en un hilo debe completarse antes de que otro pueda acceder a él.

Si imagina que la siguiente función ocurre en dos subprocesos a la vez, puede ver por qué los resultados no serían agradables.

-(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: La devolución de objetos completamente inicializados cada vez que sea la mejor opción en caso de subprocesos múltiples.

Contras: Rendimiento golpeado, hace la ejecución un poco más lenta

No atómico:

A diferencia de Atomic, no garantiza un retorno de objeto completamente inicializado cada vez.

Pros: Ejecución extremadamente rápida.

Contras: posibilidades de valor de basura en caso de subprocesos múltiples.


Antes de discutir acerca de los atributos de @property, debes saber de qué se trata el uso de @property. @property ofrece una manera de definir la información que una clase pretende encapsular. Si declara un objeto / variable usando @property, entonces ese objeto / variable será accesible a otras clases que importan su clase. Si declara un objeto usando @property en el archivo de encabezado, entonces tiene que sintetizarlo usando @synthesize en el archivo de implementación.

Ejemplo:

clase .h

@interface ExampleClass : NSObject
   @property (nonatomic, retain) NSString *name;
@end

.m clase

@implementation ExampleClass
   @synthesize name;
@end

Ahora el compilador sintetizará los métodos de acceso para el nombre.

ExampleClass *newObject=[[ExampleClass alloc]init];
NSString *name1=[newObject name]; // get 'name'
[obj setName:@“Tiger”];

Lista de atributos de @propiedad: atómica. no atómico conservar. dupdo. solo lectura. leer escribir. asignar. fuerte.

atómico: es el comportamiento por defecto. Si un objeto se declara como atómico, se vuelve seguro para subprocesos. Seguro para subprocesos significa que, al mismo tiempo, solo un subproceso de una instancia particular de esa clase puede tener el control sobre ese objeto.

Ejemplo:

@property NSString *name; //by default atomic
@property (atomic)NSString *name; // explicitly declared atomic

no atómico: no es seguro para subprocesos. Puede usar el atributo de propiedad no atómica para especificar que los accesores sintetizados simplemente establecen o devuelven un valor directamente, sin garantías sobre lo que sucede si se accede al mismo valor simultáneamente desde diferentes subprocesos. Por esta razón, es más rápido acceder a una propiedad no atómica que a una atómica. @property (nonatomic)NSString *name;

retener: se requiere cuando el atributo es un puntero a un objeto. El método de establecimiento aumentará el recuento de retenciones del objeto, de modo que ocupará la memoria en el grupo de autorelease. @property (retain)NSString *name;

copia: si usa copia, no puede usar retener. El uso de copia de la instancia de la clase contendrá su propia copia. Incluso si se establece una cadena mutable y se modifica posteriormente, la instancia captura cualquier valor que tenga en el momento en que se establece. No se sintetizarán métodos setter y getter.

@property (copy) NSString *name;

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"];

readonly: si no desea permitir que la propiedad se modifique a través del método de establecimiento, puede declarar la propiedad de solo lectura. @property (readonly) NSString *name;

readwrite: es el comportamiento predeterminado. No es necesario especificar explícitamente el atributo de escritura.

@property (readwrite) NSString *name;

asignar: generará un definidor que asigna el valor a la variable de instancia directamente, en lugar de copiarlo o retenerlo. Esto es mejor para los tipos primitivos como NSInteger y CGFloat, u objetos que no posee directamente, como los delegados.

@property (assign) NSInteger year;

fuerte: es un reemplazo para retener. @property (nonatomic, strong) AVPlayer *player;

unsafe_unretained: hay algunas clases en Cocoa y Cocoa Touch que aún no admiten referencias débiles, lo que significa que no puede declarar una propiedad débil o una variable local débil para realizar un seguimiento de ellas. Estas clases incluyen NSTextView, NSFont y NSColorSpace, etc. Si necesita usar una referencia débil para una de estas clases, debe usar una referencia no segura. Una referencia no segura es similar a una referencia débil porque no mantiene vivo el objeto relacionado, pero no se establecerá en nulo si el objeto de destino se desasigna.

@property (unsafe_unretained) NSObject *unsafeProperty;


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

Nonatomic significa que múltiples hilos acceden a la variable (tipo dinámico). No atómico no es seguro para el hilo, pero es rápido.


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

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

En el artículo Variables de propiedades o modificadores en iOS , puede encontrar todos los atributos mencionados anteriormente, y eso definitivamente lo ayudará.

  1. atomic

    • atomic significa que solo un hilo accede a la variable (tipo estático).
    • atomic es hilo seguro.
    • Pero es lento en el rendimiento.
    • atomic es el comportamiento por defecto
    • Los accesores atómicos en un entorno no recolectado de basura (es decir, cuando se utiliza retener / liberar / autorelease) usarán un bloqueo para garantizar que otra hebra no interfiera con la configuración / obtención correcta del valor.
    • No es realmente 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 hilo inseguro.
    • Pero es rápido en el rendimiento.
    • nonatomic NO es un comportamiento por defecto. Necesitamos agregar la palabra clave no nonatomic en el atributo de propiedad.
    • Puede resultar en un comportamiento inesperado, cuando dos procesos diferentes (hilos) acceden a la misma variable al mismo tiempo.

    Ejemplo:

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

El valor predeterminado es atomic , esto significa que le cuesta el rendimiento cuando usa la propiedad, pero es seguro para subprocesos. Lo que hace Objective-C es establecer un bloqueo, por lo que solo el hilo real puede acceder a la variable, siempre que se ejecute el setter / getter.

Ejemplo con MRC de una propiedad con un ivar _internal:

[_internal lock]; //lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;

Así que estos dos últimos son los mismos:

@property(atomic, retain) UITextField *userName;

@property(retain) UITextField *userName; // defaults to atomic

Por otro lado, no agrega nada nonatomic a tu código. Por lo tanto, solo es seguro para subprocesos si usted mismo codifica el mecanismo de seguridad.

@property(nonatomic, retain) UITextField *userName;

Las palabras clave no tienen que escribirse como primer atributo de propiedad.

No lo olvide, esto no significa que la propiedad en su totalidad sea segura para subprocesos. Solo la llamada al método del setter / getter es. Pero si usas un setter y luego un getter al mismo tiempo con 2 hilos diferentes, ¡también podría romperse!


Esto se explica en la documentation de Apple, pero a continuación hay algunos ejemplos de lo que realmente está sucediendo. Tenga en cuenta que no hay una palabra clave "atómica"; si no especifica "no atómica", la propiedad es atómica, pero la especificación "atómica" explícitamente generará 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 bloquearse para garantizar la seguridad del subproceso, y también está superando el recuento de referencia en el objeto (y el recuento de autoreleas para equilibrarlo) de modo que se garantice que el objeto existe para la persona que llama, de lo contrario es una condición de carrera potencial si otra hebra está configurando el valor, lo que hace que el recuento de referencia caiga a 0.

En realidad, hay un gran número de variantes diferentes de cómo funcionan estas cosas dependiendo de si las propiedades son valores u objetos escalares, y cómo interactúan retener, copiar, leer solo, no atómico, etc. En general, los sintetizadores de propiedades solo saben cómo hacer lo "correcto" para todas las combinaciones.


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

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

Esto hace que la propiedad "nombre" sea segura para lectura / escritura, pero si otro subproceso, D, llama a [name release] simultáneamente, esta operación podría producir un bloqueo porque no hay ninguna llamada de establecimiento / captador involucrada aquí. Lo que significa que un objeto es seguro para lectura / escritura (ATOMIC), pero no 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 tales objetos.

Si la propiedad "nombre" no era atómica, entonces todos los subprocesos del ejemplo anterior: A, B, C y D se ejecutarán simultáneamente y producirán un resultado impredecible. En el caso de atómico, uno de A, B o C se ejecutará primero, pero D todavía puede ejecutarse en paralelo.


La sintaxis y la semántica ya están bien definidas por otras excelentes respuestas a esta pregunta. Debido a que la ejecución y el rendimiento no están bien detallados, agregaré 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 un 100% de seguridad en la rosca es un caso de esquina. Para los programas multiproceso realmente correctos, la intervención del programador es casi ciertamente un requisito. Mientras tanto, las características de rendimiento y ejecución aún no se han detallado en profundidad. Después de haber escrito algunos programas muy multiproceso a lo largo de los años, había estado declarando mis propiedades como no nonatomic todo el tiempo porque el atómico no era sensible para ningún propósito. Durante la discusión de los detalles de las propiedades atómicas y no atómicas, esta pregunta hizo algunos perfiles y obtuve algunos resultados curiosos.

Ejecución

De acuerdo. Lo primero que me gustaría aclarar es que la implementación de bloqueo está definida y abstraída 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 utiliza realmente @synchronized(self) ; Utiliza cerraduras de giro a nivel de objeto. 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 tus objetos dentro del captador.

Actuación

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

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

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

Debido a la cantidad de optimizaciones y variaciones en las implementaciones, es bastante difícil medir los impactos del mundo real en estos contextos. Es posible que con frecuencia escuche algo como "Confíe en él, a menos que su perfil y descubra 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 llevar mucho tiempo y, debido a las abstracciones, es bastante inexacto. Además, ARC vs MRC puede hacer una gran diferencia.

Así que retrocedamos, sin centrarnos en la implementación de accesos de propiedad, incluiremos a los sospechosos habituales, como objc_msgSend , y examinaremos algunos resultados de alto nivel del mundo real para muchas llamadas a un captador de NSString en casos no NSString (valores en segundos):

  • MRC | no atómico | getters implementados manualmente: 2
  • MRC | no atómico | captador sintetizado: 7
  • MRC | atómico | captador sintetizado: 47
  • ARC | no atómico | captador sintetizado: 38 (nota: los ciclos de ref ref agregados aquí de ARC)
  • ARC | atómico | captador sintetizado: 47

Como probablemente haya adivinado, la actividad / el ciclo de conteo de referencia es un contribuyente significativo con atómica 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 prioridad baja para muchos proyectos. Sin embargo, conocer los detalles de ejecución y los costos de las tecnologías que utiliza ciertamente no daña. Debe usar la tecnología adecuada para sus necesidades, propósitos y habilidades. Esperamos que esto le ahorre algunas horas de comparaciones y le ayude a tomar una decisión mejor informada al diseñar sus programas.


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

Suponiendo que está sintetizando las implementaciones del método, atómico y no atómico cambia el código generado. Si está escribiendo su propio setter / getters, atomic / nonatomic / retain / assign / copy son meramente informativos. (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 una _ a su nombre para evitar el acceso directo accidental).

Con "atómico", el establecedor / captador sintetizado se asegurará de que siempre se devuelva un valor completo desde el captador o lo establezca, independientemente de la actividad del definidor en cualquier otro hilo. Es decir, si el subproceso A está en el medio del captador, mientras que el subproceso B llama al establecedor, se devolverá al autor de la llamada en un valor real viable (un objeto lanzado automáticamente).

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

Lo que "atómico" no hace es garantizar la seguridad de los hilos. Si el subproceso A llama al captador al mismo tiempo que el subproceso B y C llama al configurador con valores diferentes, el subproceso A puede obtener cualquiera de los tres valores devueltos: el anterior a cualquier llamador o cualquiera de los valores pasados ​​a los configuradores en B y C. Del mismo modo, el objeto puede terminar con el valor de B o C, no hay forma de saberlo.

Asegurar la integridad de los datos, uno de los principales desafíos de la programación de subprocesos múltiples, se logra por otros medios.

Añadiendo a esto:

atomicity de una sola propiedad tampoco puede garantizar la seguridad del subproceso 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 a setFirstName: y luego llamando a setLastName: Mientras tanto, el hilo B puede llamar a fullName entre las dos llamadas del hilo A y recibirá el nuevo nombre junto con el apellido anterior.

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



Propiedades atómicas : cuando una variable asignada con propiedad atómica significa que solo tiene acceso a un subproceso y que será segura para subprocesos y será buena en la perspectiva del rendimiento, tendrá un comportamiento predeterminado.

Propiedades no atómicas : cuando una variable asignada con propiedad atómica significa que tiene acceso a múltiples subprocesos y no será segura para los subprocesos y será lenta en la perspectiva del rendimiento, tendrá un comportamiento predeterminado y cuando dos subprocesos diferentes quieran acceder a la variable al mismo tiempo Dará resultados inesperados.


La propiedad atómica garantiza la retención de un valor completamente inicializado, independientemente de la cantidad de subprocesos que estén haciendo getter y setter en él.

La propiedad no atómica especifica que los accesores sintetizados simplemente establecen o devuelven un valor directamente, sin garantías sobre lo que sucede si se accede al mismo valor simultáneamente desde diferentes subprocesos.


Para simplificar toda la confusión, entendamos el bloqueo mutex. El bloqueo mutex de acuerdo con el nombre bloquea la mutabilidad del objeto. Por lo tanto, si una clase no puede acceder al mismo objeto, otra clase puede acceder al mismo objeto. En iOS @sychronise también proporciona el mutex bloquear. Ahora sirve en modo FIFO y garantiza que el flujo no se vea afectado por dos clases que comparten la misma instancia. Sin embargo, si la tarea está en el hilo principal, evite acceder al objeto utilizando propiedades atómicas, ya que puede contener su interfaz de usuario y degradar el rendimiento.


Atómico significa que solo un hilo puede acceder a la variable a la vez (tipo estático). Atomic es seguro para los hilos, pero es lento.

Nonatomic significa que múltiples hilos pueden acceder a la variable al mismo tiempo (tipo dinámico). No atómico no es seguro para el hilo, pero es rápido.


La verdad es que utilizan el bloqueo de giro para implementar la propiedad atómica. El código de la siguiente manera:

 static inline void reallySetProperty(id self, SEL _cmd, id newValue, 
      ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) 
    {
        id oldValue;
        id *slot = (id*) ((char*)self + offset);

        if (copy) {
            newValue = [newValue copyWithZone:NULL];
        } else if (mutableCopy) {
            newValue = [newValue mutableCopyWithZone:NULL];
        } else {
            if (*slot == newValue) return;
            newValue = objc_retain(newValue);
        }

        if (!atomic) {
            oldValue = *slot;
            *slot = newValue;
        } else {
            spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
            _spin_lock(slotlock);
            oldValue = *slot;
            *slot = newValue;        
            _spin_unlock(slotlock);
        }

        objc_release(oldValue);
    }

Si está utilizando su propiedad en código de subprocesos múltiples, entonces podrá ver la diferencia entre atributos atómicos y no atómicos. Nonatomic es más rápido que atomic y atomic es seguro para subprocesos, no no atómico.

Vijayendra Tripathi ya ha dado un ejemplo para un entorno de subprocesos múltiples.


  • -Atómico significa que solo un hilo accede a la variable (tipo estático).
  • -Atómico es hilo seguro.
  • -pero es lento en el rendimiento

Cómo declarar:

Como el atómico es por defecto así,

@property (retain) NSString *name;

Y en el archivo de implementación

self.name = @"sourov";

Supongamos que una tarea relacionada con tres propiedades es

 @property (retain) NSString *name;
 @property (retain) NSString *A;
 @property (retain) NSString *B;
 self.name = @"sourov";

Todas las propiedades funcionan en paralelo (como asincrónicamente).

Si llamas "nombre" desde el hilo A ,

Y

Al mismo tiempo si llamas

[self setName:@"Datta"]

del hilo B ,

Ahora si * la propiedad de nombre no es atómica entonces

  • Devolverá el valor "Datta" para A
  • Devolverá el valor "Datta" para B

Es por eso que no atómico se llama hilo inseguro, pero es rápido en el rendimiento debido a la ejecución paralela

Ahora si * la propiedad del nombre es atómica

  • Se asegurará el valor "Sourov" para A
  • Luego devolverá el valor "Datta" para B

Es por eso que atomic se llama hilo seguro y por eso se llama lectura-escritura segura

Dicha operación de situación se realizará en serie. Y lento en el rendimiento

- Nonatomic significa acceso múltiple a la variable (tipo dinámico).

- Nonatomic es hilo inseguro.

- pero es rápido en el rendimiento

-Nonatomic no es un comportamiento predeterminado, necesitamos agregar una palabra clave no atómica en el atributo de propiedad.

Para In Swift Confirmando que las propiedades Swift no son atómicas en el sentido de ObjC. Una razón es que piense si la atomicidad por propiedad es suficiente para sus necesidades.

Referencia: https://forums.developer.apple.com/thread/25642

Para obtener más información, visite el sitio web http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html







nonatomic