อะไรคือความแตกต่างระหว่างแอตทริบิวต์ของอะตอมและไม่ใช่ของอะตอม?


1851

สิ่งใดatomicและมีความnonatomicหมายในการประกาศทรัพย์สิน?

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

ความแตกต่างในการดำเนินงานระหว่างสามสิ่งนี้คืออะไร


คำตอบ:


1761

สองอันสุดท้ายเหมือนกัน "atomic" เป็นพฤติกรรมเริ่มต้น ( โปรดทราบว่ามันไม่ได้เป็นคำหลักจริงมันมีการระบุเพียงโดยไม่มีnonatomic -atomicถูกเพิ่มเป็นคำหลักในรุ่นล่าสุดของ llvm / clang)

สมมติว่าคุณเป็น @synthesizing วิธีการใช้งาน, atomic เทียบกับที่ไม่ใช่อะตอมเปลี่ยนรหัสที่สร้างขึ้น หากคุณกำลังเขียน setter / getters ของคุณเอง atomic / nonatomic / keep / assign / copy เป็นเพียงคำแนะนำ (หมายเหตุ: @synthesize ตอนนี้เป็นพฤติกรรมเริ่มต้นใน LLVM รุ่นล่าสุดนอกจากนี้ยังไม่จำเป็นต้องประกาศตัวแปรอินสแตนซ์พวกเขาจะถูกสังเคราะห์โดยอัตโนมัติเช่นกันและจะมีการเติม_ลงในชื่อของพวกเขาเพื่อป้องกันการเข้าถึงโดยตรงโดยไม่ตั้งใจ)

ด้วย "atomic" setter / getter ที่สังเคราะห์จะทำให้มั่นใจว่าค่าทั้งหมดจะถูกส่งคืนจาก getter หรือ setter โดย setter เสมอโดยไม่คำนึงถึงกิจกรรม setter ในเธรดอื่น ๆ นั่นคือถ้าเธรด A อยู่ตรงกลางของ getter ขณะที่เธรด B เรียก setter ค่าที่ทำงานได้จริง - ออบเจ็กต์ autoreleded มีแนวโน้มมากที่สุด - จะถูกส่งคืนไปยังผู้เรียกใน A

ในnonatomicไม่มีการค้ำประกันดังกล่าว ดังนั้นจึงnonatomicเร็วกว่า "อะตอม" มาก

อะไร "อะตอมมิก" ไม่ได้ทำคือการรับประกันใด ๆ เกี่ยวกับความปลอดภัยของด้าย หากเธรด A กำลังเรียกใช้ getter พร้อมกันโดยมีเธรด B และ C เรียก setter ที่มีค่าต่างกันเธรด A อาจรับค่าใดค่าหนึ่งในสามค่าที่ส่งคืน - ค่าก่อนหน้าตัวตั้งค่าใด ๆ ที่ถูกเรียกหรือค่าใดค่าหนึ่ง ใน B และ C เช่นเดียวกันวัตถุอาจท้ายด้วยค่าจาก B หรือ C ไม่มีทางที่จะบอก

การรับรองความถูกต้องของข้อมูล - หนึ่งในความท้าทายหลักของการเขียนโปรแกรมแบบมัลติเธรด - ทำได้ด้วยวิธีการอื่น

เพิ่มไปนี้:

atomicity ของคุณสมบัติเดียวยังไม่สามารถรับประกันความปลอดภัยของเธรดเมื่อมีคุณสมบัติที่ต้องพึ่งพาหลายรายการในการเล่น

พิจารณา:

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

ในกรณีนี้ด้ายอาจจะเปลี่ยนชื่อวัตถุโดยการโทรแล้วโทรsetFirstName: setLastName:ในระหว่างนี้เธรด B อาจเรียกfullNameระหว่างการโทรสองสายของเธรด A และจะได้รับชื่อใหม่ควบคู่กับนามสกุลเก่า

เพื่อแก้ปัญหานี้คุณจำเป็นต้องมีรูปแบบการทำธุรกรรม คือการซิงโครไนซ์และ / หรือการแยกประเภทอื่น ๆ ที่อนุญาตให้ผู้ใช้หนึ่งคนยกเว้นการเข้าถึงfullNameในขณะที่คุณสมบัติที่ต้องพึ่งพากำลังได้รับการอัปเดต


21
ระบุว่ารหัส thread-safe จะทำการล็อคตัวเอง ฯลฯ เมื่อใดที่คุณต้องการใช้ accessors คุณสมบัติอะตอมมิก ฉันมีปัญหาในการคิดตัวอย่างที่ดี
Daniel Dickison

8
@bum ทำให้รู้สึก ฉันชอบความคิดเห็นของคุณต่อคำตอบอื่นที่ความปลอดภัยของเธรดนั้นเป็นปัญหาระดับโมเดลมากกว่า จากคำจำกัดความความปลอดภัยของเธรด IBM: ibm.co/yTEbjY "ถ้ามีการใช้งานคลาสอย่างถูกต้องซึ่งเป็นอีกวิธีหนึ่งในการบอกว่าสอดคล้องกับข้อกำหนดของมันไม่มีลำดับของการดำเนินการ (อ่านหรือเขียนของฟิลด์สาธารณะและการเรียกใช้วิธีสาธารณะ) บนวัตถุของคลาสนั้นควรจะสามารถทำให้วัตถุนั้นอยู่ในสถานะที่ไม่ถูกต้องสังเกตวัตถุที่อยู่ในสถานะที่ไม่ถูกต้องหรือละเมิดค่าคงที่เงื่อนไขหรือเงื่อนไข postconditions ใด ๆ ของชั้นเรียน
Ben Flynn

6
นี่คือตัวอย่างที่คล้ายกับ @StevenKramer: ฉันมี@property NSArray* astronomicalEvents;รายการที่แสดงข้อมูลที่ฉันต้องการแสดงใน UI เมื่อแอปพลิเคชันเปิดใช้งานตัวชี้ชี้ไปที่อาร์เรย์ที่ว่างเปล่าแอปจะดึงข้อมูลจากเว็บ เมื่อคำขอของเว็บเสร็จสมบูรณ์ (ในเธรดอื่น) แอปจะสร้างอาร์เรย์ใหม่จากนั้นจึงตั้งค่าคุณสมบัติเป็นอะตอมตัวชี้ใหม่ มันปลอดภัยและไม่ต้องเขียนรหัสล็อคยกเว้นว่าฉันทำอะไรหายไป ดูเหมือนว่ามีประโยชน์กับฉัน
bugloaf

10
@ HotLicks อีกหนึ่งความสนุก ในสถาปัตยกรรมบางอย่าง (จำไม่ได้ว่าอันไหน) ค่า 64 บิตที่ส่งผ่านเป็นอาร์กิวเมนต์อาจถูกส่งผ่านครึ่งหนึ่งในรีจิสเตอร์และครึ่งหนึ่งบนสแต็ก atomicป้องกันการอ่านค่าครึ่งค่าข้ามเธรด (นั่นเป็นข้อผิดพลาดที่สนุกที่จะตามหา)
bbum

8
@congliu Thread A ส่งคืนวัตถุโดยไม่มีretain/autoreleaseการเต้นรำ เธรด B ปล่อยวัตถุ ด้ายไปบูม atomicตรวจสอบให้แน่ใจว่าเธรด A มีการอ้างอิงที่รัดกุม (จำนวนการเก็บรักษา +1) สำหรับค่าส่งคืน
bbum

360

นี่คือคำอธิบายในเอกสารของ Apple แต่ด้านล่างเป็นตัวอย่างของสิ่งที่เกิดขึ้นจริง

โปรดทราบว่าไม่มีคำหลัก "atomic" หากคุณไม่ได้ระบุ "nonatomic" คุณสมบัติจะเป็น atomic แต่การระบุ "atomic" อย่างชัดเจนจะส่งผลให้เกิดข้อผิดพลาด

หากคุณไม่ได้ระบุ "nonatomic" แสดงว่าคุณสมบัตินั้นเป็น atomic แต่คุณยังสามารถระบุ "atomic" ได้อย่างชัดเจนในเวอร์ชันล่าสุดหากคุณต้องการ

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

- (UITextField *) userName {
    return userName;
}

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

ทีนี้ตัวแปรอะตอมก็ซับซ้อนขึ้นอีกเล็กน้อย:

//@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_;
    }
}

โดยทั่วไปแล้วรุ่นอะตอมจะต้องทำการล็อคเพื่อรับประกันความปลอดภัยของเธรดและยังมีการนับจำนวนการอ้างอิงบนวัตถุ (และการนับจำนวนอัตโนมัติเพื่อปรับสมดุล) เพื่อให้วัตถุรับประกันว่าจะมีอยู่สำหรับผู้โทรมิฉะนั้นจะมี เป็นสภาพการแข่งขันที่อาจเกิดขึ้นหากเธรดอื่นตั้งค่าไว้ทำให้นับการนับลดลงเป็น 0

ในความเป็นจริงมีความแตกต่างหลากหลายของวิธีการทำงานของสิ่งเหล่านี้ขึ้นอยู่กับว่าคุณสมบัติเป็นค่าสเกลาร์หรือวัตถุและวิธีการเก็บรักษาคัดลอกอ่านอย่างเดียวไม่ทำงานเชิงอะตอม ฯลฯ โดยทั่วไปแล้วซินธิไซเซอร์จะรู้วิธีการทำสิ่งที่ถูกต้องสำหรับชุดค่าผสม


8
@Louis Gerbarg: ฉันเชื่อว่ารุ่นของคุณ (ไม่ทำงาน, เก็บไว้) setter จะทำงานไม่ถูกต้องหากคุณพยายามที่จะกำหนดวัตถุเดียวกัน (นั่นคือ: ชื่อผู้ใช้ == ชื่อผู้ใช้ _)
Florin

5
รหัสของคุณทำให้เข้าใจผิดเล็กน้อย มีไม่มีการรับประกันเกี่ยวกับสิ่งที่ getters อะตอม / setters ที่ตรงกัน วิกฤต@property (assign) id delegate;จะไม่ตรงกันในสิ่งที่ (iOS SDK GCC 4.2 ARM -Os) ซึ่งหมายความว่ามีการแข่งขันระหว่างและ[self.delegate delegateMethod:self]; foo.delegate = nil; self.foo = nil; [super dealloc];ดูstackoverflow.com/questions/917884/…
tc

@fyolnish ผมไม่แน่ใจว่าสิ่งที่_val/ valมี แต่ไม่ได้จริงๆ ผู้ทะเยอทะยานสำหรับอะตอมมิกcopy/ retainทรัพย์สินจำเป็นต้องตรวจสอบให้แน่ใจว่ามันจะไม่ส่งคืนวัตถุที่ refcount กลายเป็นศูนย์เนื่องจาก setter ถูกเรียกในเธรดอื่นซึ่งจำเป็นต้องอ่านไอวาร์เก็บไว้ในขณะที่มั่นใจว่าเซ็ตเตอร์ไม่ได้ เขียนทับและปล่อยแล้วปิดอัตโนมัติเพื่อปรับสมดุลการรักษา นั่นหมายความว่าทั้ง getter และ setter ต้องใช้การล็อก (ถ้าเลย์เอาต์ของหน่วยความจำคงที่มันควรจะทำได้ด้วยคำสั่ง CAS2; อนิจจา-retainเป็นการเรียกเมธอด)
tc

@tc มันค่อนข้างนาน แต่สิ่งที่ฉันตั้งใจจะเขียนอาจเป็นเช่นนี้: gist.github.com/fjolnir/5d96b3272c6255f6baaeแต่ใช่มันเป็นไปได้ที่ค่าเก่าจะอ่านโดยผู้อ่านก่อน setFoo: return และปล่อยก่อน ผู้อ่านส่งคืนมัน แต่บางทีถ้าผู้ตั้งค่าใช้ -autorelease แทน -release นั่นจะแก้ไขได้
Fjölnir

@ fyolnish แต่น่าเสียดายที่ไม่ใช่: autoreleases ที่อยู่บนเธรดของ setter ในขณะที่มันต้องถูก autorelease บนเธรดของ getter ดูเหมือนว่ายังมีโอกาส (บาง) ที่จะหมดสแต็กเพราะคุณใช้การเรียกซ้ำ
tc

170

อะตอม

  • เป็นพฤติกรรมเริ่มต้น
  • จะทำให้แน่ใจว่ากระบวนการปัจจุบันเสร็จสมบูรณ์โดย CPU ก่อนที่กระบวนการอื่นเข้าถึงตัวแปร
  • ไม่รวดเร็วเนื่องจากช่วยให้มั่นใจว่ากระบวนการจะเสร็จสมบูรณ์ทั้งหมด

Non-ปรมาณู

  • ไม่ใช่พฤติกรรมเริ่มต้น
  • เร็วขึ้น (สำหรับรหัสสังเคราะห์นั่นคือสำหรับตัวแปรที่สร้างขึ้นโดยใช้ @property และ @synthesize)
  • ไม่ปลอดภัยสำหรับเธรด
  • อาจส่งผลให้เกิดพฤติกรรมที่ไม่คาดคิดเมื่อกระบวนการที่แตกต่างกันสองกระบวนการเข้าถึงตัวแปรเดียวกันในเวลาเดียวกัน

137

วิธีที่ดีที่สุดที่จะเข้าใจความแตกต่างคือการใช้ตัวอย่างต่อไปนี้

สมมติว่ามีคุณสมบัติสตริงอะตอมมิกที่เรียกว่า "ชื่อ" และถ้าคุณโทร[self setName:@"A"]จากเธรด A โทร[self setName:@"B"]จากเธรด B และโทร[self name]จากเธรด C ดังนั้นการดำเนินการทั้งหมดในเธรดที่แตกต่างกันจะดำเนินการตามลำดับซึ่งหมายความว่าหากเธรดหนึ่ง หรือทะเยอทะยานแล้วหัวข้ออื่น ๆ จะรอ

สิ่งนี้ทำให้คุณสมบัติ "ชื่อ" อ่าน / เขียนปลอดภัย แต่หากเธรดอื่น, D, การโทร[name release]พร้อมกันการดำเนินการนี้อาจทำให้เกิดความผิดพลาดเนื่องจากไม่มีการเรียก setter / getter ที่เกี่ยวข้อง ซึ่งหมายความว่าวัตถุนั้นปลอดภัยในการอ่าน / เขียน (ATOMIC) แต่ไม่ปลอดภัยกับเธรดเนื่องจากเธรดอื่นสามารถส่งข้อความประเภทใดก็ได้ไปยังวัตถุพร้อมกัน นักพัฒนาควรตรวจสอบความปลอดภัยของเธรดสำหรับวัตถุดังกล่าว

หากคุณสมบัติ "ชื่อ" ไม่ใช่คุณสมบัติดังนั้นเธรดทั้งหมดในตัวอย่างด้านบน - A, B, C และ D จะดำเนินการพร้อมกันเพื่อสร้างผลลัพธ์ที่คาดเดาไม่ได้ ในกรณีของอะตอมหนึ่งใน A, B หรือ C จะดำเนินการก่อน แต่ D ยังคงสามารถทำงานแบบขนานได้


116

ไวยากรณ์และความหมายถูกกำหนดไว้อย่างดีโดยคำตอบที่ยอดเยี่ยมอื่น ๆ สำหรับคำถามนี้ เนื่องจากการดำเนินการและประสิทธิภาพไม่ละเอียดฉันจะเพิ่มคำตอบของฉัน

ความแตกต่างในการทำงานระหว่าง 3 เหล่านี้คืออะไร?

ฉันมักจะถือว่าอะตอมเป็นค่าเริ่มต้นค่อนข้างอยากรู้อยากเห็น ในระดับนามธรรมที่เราทำงานโดยใช้คุณสมบัติอะตอมมิกสำหรับคลาสเป็นยานพาหนะเพื่อให้ได้ความปลอดภัยของด้าย 100% เป็นกรณีมุม สำหรับโปรแกรมแบบมัลติเธรดที่ถูกต้องอย่างแท้จริงการแทรกแซงโดยโปรแกรมเมอร์นั้นเป็นสิ่งจำเป็นอย่างยิ่ง ในขณะเดียวกันคุณลักษณะด้านประสิทธิภาพและการดำเนินการยังไม่ได้รับการอธิบายอย่างละเอียด หลายปีที่ผ่านมาฉันได้เขียนโปรแกรมที่มีหลายเธรดอย่างหนักฉันได้ประกาศคุณสมบัติของฉันnonatomicตลอดเวลาเพราะปรมาณูไม่เหมาะสมสำหรับวัตถุประสงค์ใด ๆ ในระหว่างการอภิปรายรายละเอียดของคุณสมบัติอะตอมและไม่ใช่อะตอมคำถามนี้ฉันทำโปรไฟล์บางอย่างพบผลลัพธ์บางอย่างอยากรู้อยากเห็น

การกระทำ

ตกลง. สิ่งแรกที่ฉันต้องการจะล้างคือการนำการล็อกไปใช้กำหนดและการนำไปใช้งาน หลุยส์ใช้@synchronized(self)ในตัวอย่างของเขา - ฉันได้เห็นสิ่งนี้ว่าเป็นแหล่งของความสับสน การใช้งานจริงไม่ได้ใช้@synchronized(self); จะใช้ระดับวัตถุหมุนล็อค ภาพประกอบของหลุยส์เป็นสิ่งที่ดีสำหรับภาพประกอบระดับสูงโดยใช้โครงสร้างที่เราทุกคนคุ้นเคยกับ @synchronized(self)แต่มันเป็นสิ่งสำคัญที่จะรู้ว่ามันไม่ได้ใช้งาน

ความแตกต่างก็คือคุณสมบัติของอะตอมจะรักษา / ปล่อยวัฏจักรวัตถุของคุณภายในทะเยอทะยาน

ประสิทธิภาพ

นี่คือส่วนที่น่าสนใจ: ประสิทธิภาพการทำงานโดยใช้คุณสมบัติของอะตอมมิกในกรณีที่ไม่มีการโต้แย้ง (เช่นเธรดเดี่ยว) อาจเร็วมากในบางกรณี ในเวลาที่น้อยกว่าเหมาะกรณีใช้เข้าถึงอะตอมสามารถค่าใช้จ่ายมากกว่า 20 nonatomicครั้งค่าใช้จ่ายของ ในขณะที่กรณีContested ที่ใช้ 7 เธรดนั้นช้ากว่า 44 เท่าสำหรับโครงสร้างสามไบต์ (2.2 GHz Core i7 Quad Core, x86_64) struct สามไบต์เป็นตัวอย่างของคุณสมบัติช้ามาก

หมายเหตุด้านที่น่าสนใจ: accessors ที่ผู้ใช้กำหนดเองของโครงสร้างสามไบต์เร็วกว่าตัวสังเคราะห์แบบ atomic accessors 52 เท่า; หรือ 84% ความเร็วของการสังเคราะห์ accessor nonatomic

วัตถุในกรณีที่โต้แย้งอาจเกิน 50 ครั้ง

เนื่องจากจำนวนของการปรับให้เหมาะสมและความผันแปรของการนำไปใช้งานจึงค่อนข้างยากที่จะวัดผลกระทบที่เกิดขึ้นจริงในบริบทเหล่านี้ คุณมักจะได้ยินอะไรบางอย่างเช่น "เชื่อใจคุณนอกจากโปรไฟล์และพบว่าเป็นปัญหา" เนื่องจากระดับนามธรรมมันจึงค่อนข้างยากที่จะวัดผลกระทบที่เกิดขึ้นจริง การรวบรวมค่าใช้จ่ายจริงจากโปรไฟล์อาจใช้เวลานานมากและเนื่องจากมีการสรุปที่ไม่ถูกต้อง ARC กับ MRC ก็สามารถสร้างความแตกต่างได้เช่นกัน

ดังนั้นย้อนกลับไปไม่ได้มุ่งเน้นไปที่การใช้งานการเข้าถึงคุณสมบัติเราจะรวมผู้ต้องสงสัยตามปกติobjc_msgSendและตรวจสอบผลลัพธ์ระดับสูงในโลกแห่งความจริงสำหรับการโทรไปยังผู้เรียกหลายคนNSStringในกรณีที่ไม่มีการโต้แย้ง (ค่าในไม่กี่วินาที):

  • MRC | nonatomic | getters ที่ใช้งานด้วยตนเอง: 2
  • MRC | nonatomic | ทะเยอทะยานสังเคราะห์: 7
  • MRC | อะตอม ทะเยอทะยานสังเคราะห์: 47
  • ARC | nonatomic | synthesized getter: 38 (หมายเหตุ: การนับการอ้างอิงของ ARC เพิ่มที่นี่)
  • ARC | อะตอม ทะเยอทะยานสังเคราะห์: 47

ในขณะที่คุณคาดเดากิจกรรมการนับการอ้างอิง / การขี่จักรยานเป็นผู้มีส่วนร่วมสำคัญกับอะตอมมิกและภายใต้ ARC คุณจะเห็นความแตกต่างที่มากขึ้นในกรณีที่ถูกโต้แย้ง

แม้ว่าฉันจะใส่ใจกับการแสดงอย่างมาก แต่ฉันก็ยังพูดถึงความหมายก่อน! . ในขณะเดียวกันประสิทธิภาพมีความสำคัญต่ำสำหรับหลาย ๆ โครงการ อย่างไรก็ตามการรู้รายละเอียดการดำเนินการและค่าใช้จ่ายของเทคโนโลยีที่คุณใช้อย่างแน่นอนไม่ได้ทำให้เจ็บปวด คุณควรใช้เทคโนโลยีที่เหมาะสมกับความต้องการวัตถุประสงค์และความสามารถของคุณ หวังว่านี่จะช่วยให้คุณประหยัดเวลาในการเปรียบเทียบสองสามชั่วโมงและช่วยให้คุณตัดสินใจได้ดีขึ้นเมื่อออกแบบโปรแกรมของคุณ


MRC | อะตอม synthesized getter: 47 ARC | อะตอม synthesized getter: 47 อะไรที่ทำให้พวกมันเหมือนกัน? ARC ไม่ควรมีค่าใช้จ่ายมากกว่านี้ใช่ไหม
SDEZero

2
ดังนั้นถ้าคุณสมบัติของอะตอมไม่ดี y พวกมันจะเป็นค่าปริยาย เพื่อเพิ่มรหัสสำเร็จรูป?
Kunal Balani

@ LearnCocos2D ฉันเพิ่งทดสอบบน 10.8.5 บนเครื่องเดียวกันโดยมีเป้าหมาย 10.8 สำหรับกรณีที่ไม่มีการโต้แย้งแบบเธรดเดี่ยวNSStringซึ่งไม่เป็นอมตะ: -ARC atomic (BASELINE): 100% -ARC nonatomic, synthesised: 94% -ARC nonatomic, user defined: 86% -MRC nonatomic, user defined: 5% -MRC nonatomic, synthesised: 19% -MRC atomic: 102%- ผลลัพธ์จะแตกต่างกันเล็กน้อยในวันนี้ ฉันไม่ได้ทำการ@synchronizedเปรียบเทียบใด ๆ @synchronizedแตกต่างเชิงความหมายและฉันไม่คิดว่ามันเป็นเครื่องมือที่ดีถ้าคุณมีโปรแกรมที่ไม่เกิดขึ้นพร้อมกัน @synchronizedถ้าคุณต้องการความเร็วในการหลีกเลี่ยง
justin

คุณมีการทดสอบออนไลน์ที่อื่นไหม ฉันจะเพิ่มของฉันที่นี่: github.com/LearnCocos2D/LearnCocos2D/tree/master/…
LearnCocos2D

@ LearnCocos2D ฉันยังไม่ได้เตรียมไว้สำหรับการบริโภคของมนุษย์ขอโทษ
justin

95

Atomic = thread safety

ปลอดปรมาณู = ไม่ปลอดภัยต่อเธรด

ความปลอดภัยด้าย:

ตัวแปรอินสแตนซ์จะปลอดภัยต่อเธรดหากทำงานอย่างถูกต้องเมื่อเข้าถึงจากหลายเธรดโดยไม่คำนึงถึงการกำหนดเวลาหรือการสอดแทรกการประมวลผลเธรดเหล่านั้นตามสภาพแวดล้อมรันไทม์และไม่มีการซิงโครไนซ์เพิ่มเติมหรือการประสานงานอื่น ๆ

ในบริบทของเรา:

หากเธรดเปลี่ยนค่าของอินสแตนซ์ค่าที่เปลี่ยนแปลงจะพร้อมใช้งานสำหรับเธรดทั้งหมดและมีเพียงเธรดเดียวเท่านั้นที่สามารถเปลี่ยนค่าในแต่ละครั้ง

ใช้ที่ไหนatomic:

ถ้าตัวแปรอินสแตนซ์จะถูกเข้าถึงในสภาพแวดล้อมแบบมัลติเธรด

ความหมายของatomic:

ไม่เร็วเท่าnonatomicเพราะnonatomicไม่ต้องการสุนัขเฝ้ายามทำงานบนรันไทม์

ใช้ที่ไหนnonatomic:

หากตัวแปรอินสแตนซ์ไม่ได้ถูกเปลี่ยนโดยหลายเธรดคุณสามารถใช้งานได้ มันช่วยเพิ่มประสิทธิภาพ


3
ทุกสิ่งที่คุณพูดที่นี่ถูกต้อง แต่ประโยคสุดท้ายคือ "ผิด" โดย Dura สำหรับการเขียนโปรแกรมของวันนี้ เป็นไปไม่ได้จริงๆที่คุณจะพยายาม "ปรับปรุงประสิทธิภาพ" ด้วยวิธีนี้ (ฉันหมายถึงก่อนที่คุณจะอยู่ในช่วงปีที่แล้วคุณจะเป็น "ไม่ได้ใช้ ARC", "ไม่ใช้ NSString เพราะมันช้า!" เป็นต้น) เพื่อให้เป็นตัวอย่างที่ยอดเยี่ยมมันจะเหมือนกับการพูดว่า "ทีม อย่าใส่ความคิดเห็นลงในโค้ดเพราะจะทำให้เราช้าลง " ไม่มีขั้นตอนการพัฒนาที่สมจริงที่คุณต้องการให้ประสิทธิภาพทางทฤษฎี (ไม่มีอยู่) เพิ่มขึ้นเพราะความไม่น่าเชื่อถือ
Fattie

3
@JoeBlow เป็นความจริงคุณสามารถตรวจสอบได้ที่นี่developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan.H

1
Durai, FWIW, ลิงค์ที่ขัดแย้งโดยตรงกับวิทยานิพนธ์ของคุณของ "Atomic = thread safety" ในเอกสาร Apple ระบุอย่างชัดเจนว่า“ อะตอมมิกซิตี้คุณสมบัติไม่ได้มีความหมายเหมือนกันกับความปลอดภัยของเธรดของวัตถุ” ในทางปฏิบัติอะตอมไม่เพียงพอที่จะบรรลุความปลอดภัยของเธรด
Rob

69

ผมพบว่าคำอธิบายใส่สวยดีของคุณสมบัติของอะตอมและไม่ใช่อะตอมที่นี่ นี่คือข้อความที่เกี่ยวข้องจากเดียวกัน:

'อะตอมมิก' หมายความว่ามันจะไม่ถูกทำลาย ในแง่ของ OS / การเขียนโปรแกรมการเรียกใช้ฟังก์ชั่นอะตอมมิกนั้นเป็นสิ่งที่ไม่สามารถถูกขัดจังหวะได้ - ทั้งฟังก์ชั่นจะต้องถูกดำเนินการและไม่ถูกสลับจาก CPU โดยการสลับบริบทตามปกติของระบบปฏิบัติการจนกว่าจะเสร็จสมบูรณ์ ในกรณีที่คุณไม่ทราบ: เนื่องจาก CPU สามารถทำสิ่งหนึ่งครั้งเท่านั้นระบบปฏิบัติการจะหมุนการเข้าถึง CPU ไปยังกระบวนการที่กำลังทำงานทั้งหมดในเวลาเพียงเล็กน้อยเพื่อให้เห็นภาพลวงตาการทำงานหลายอย่าง ตัวกำหนดตารางเวลาของ CPU สามารถ (และไม่) ขัดจังหวะกระบวนการ ณ จุดใด ๆ ในการดำเนินการของ - แม้ในการเรียกฟังก์ชั่นกลาง ดังนั้นสำหรับการกระทำเช่นการอัปเดตตัวแปรตัวนับที่ใช้ร่วมกันซึ่งทั้งสองกระบวนการสามารถพยายามปรับปรุงตัวแปรในเวลาเดียวกันพวกเขาจะต้องถูกเรียกใช้งานแบบ 'อะตอม' เช่น

ดังนั้นฉันจึงคาดเดาว่าอะตอมในกรณีนี้หมายความว่าเมธอดตัวอ่านแอ็ตทริบิวต์ไม่สามารถถูกขัดจังหวะได้ - หมายความว่าตัวแปรที่อ่านด้วยวิธีนี้ไม่สามารถเปลี่ยนค่าได้ครึ่งทางเนื่องจากเธรด / การโทร / ฟังก์ชั่นอื่น ๆ เปลี่ยนเป็นซีพียู

เพราะatomicตัวแปรไม่สามารถขัดจังหวะค่าที่มีอยู่โดยพวกเขาที่จุดใดคือ (ด้ายล็อค) รับประกันว่าจะไม่เสียหายแม้ว่าการสร้างความมั่นใจล็อคกระทู้นี้จะทำให้การเข้าถึงพวกเขาช้าลง non-atomicในทางตรงกันข้ามตัวแปรไม่รับประกันเช่นนั้น แต่ให้ความหรูหราในการเข้าถึงที่รวดเร็วยิ่งขึ้น ในการสรุปให้ไปด้วยnon-atomicเมื่อคุณรู้ว่าตัวแปรของคุณจะไม่สามารถเข้าถึงได้โดยหลายเธรดพร้อมกันและเพิ่มความเร็ว


1
ลิงก์เสีย ;
Rob

นั่นเป็นปัญหาของลิงก์ :( โชคดีที่ฉันได้ยกข้อความที่เกี่ยวข้องในคำตอบของฉัน
tipycalFlow

67

หลังจากอ่านบทความมากมาย, โพสต์ Stack Overflow และสร้างแอพพลิเคชั่นตัวอย่างเพื่อตรวจสอบคุณสมบัติของคุณสมบัติตัวแปร, ฉันตัดสินใจที่จะรวบรวมข้อมูลคุณสมบัติทั้งหมดเข้าด้วยกัน:

  1. atomic // ค่าเริ่มต้น
  2. nonatomic
  3. strong = retain // ค่าเริ่มต้น
  4. weak = unsafe_unretained
  5. retain
  6. assign // ค่าเริ่มต้น
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite // ค่าเริ่มต้น

ในบทความคุณสมบัติคุณสมบัติตัวแปรหรือตัวดัดแปลงใน iOSคุณสามารถค้นหาคุณลักษณะที่กล่าวถึงข้างต้นทั้งหมดและนั่นจะช่วยคุณได้อย่างแน่นอน

  1. atomic

    • atomic หมายถึงเพียงหนึ่งเธรดที่เข้าถึงตัวแปร (ชนิดคงที่)
    • atomic ด้ายปลอดภัย
    • แต่ประสิทธิภาพก็ช้า
    • atomic เป็นพฤติกรรมเริ่มต้น
    • ตัวเข้าถึงอะตอมมิกในสภาพแวดล้อมที่ไม่ได้รวบรวมขยะ (เช่นเมื่อใช้การเก็บรักษา / ปล่อย / การเลิกอัตโนมัติ) จะใช้การล็อกเพื่อให้แน่ใจว่าเธรดอื่นไม่รบกวนการตั้งค่า / การรับค่าที่ถูกต้อง
    • มันไม่ได้เป็นคำหลักจริงๆ

    ตัวอย่าง:

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

    • nonatomic หมายถึงหลายเธรดเข้าถึงตัวแปร (ชนิดไดนามิก)
    • nonatomic ไม่ปลอดภัยต่อเธรด
    • แต่ประสิทธิภาพก็เร็ว
    • nonatomicไม่ใช่พฤติกรรมเริ่มต้น เราจำเป็นต้องเพิ่มnonatomicคำหลักในคุณสมบัติของคุณสมบัติ
    • มันอาจส่งผลให้พฤติกรรมที่ไม่คาดคิดเมื่อทั้งสองกระบวนการที่แตกต่างกัน (กระทู้) เข้าถึงตัวแปรเดียวกันในเวลาเดียวกัน

    ตัวอย่าง:

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

การมอบหมายและแข็งแรง / รักษาทั้งสองเป็นค่าเริ่มต้นได้อย่างไร
BangOperator

แข็งแกร่งมาพร้อมกับ ARC รักษาเป็นค่าเริ่มต้นก่อน ARC
abdullahselek

56

อะตอม:

ปรมาณูรับประกันว่าการเข้าถึงทรัพย์สินจะดำเนินการในลักษณะปรมาณู เช่นจะส่งคืนออบเจ็กต์ที่ถูกกำหนดค่าเริ่มต้นอย่างสมบูรณ์เสมอการรับ / ชุดของคุณสมบัติบนเธรดหนึ่งจะต้องเสร็จสิ้นก่อนที่อีกอันจะสามารถเข้าถึงได้

หากคุณนึกภาพฟังก์ชั่นต่อไปนี้เกิดขึ้นในสองเธรดในคราวเดียวคุณจะเห็นว่าทำไมผลลัพธ์ไม่สวย

-(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;
  }

  ...
}

ข้อดี: การ กลับมาของวัตถุที่เริ่มต้นอย่างสมบูรณ์ในแต่ละครั้งทำให้เป็นตัวเลือกที่ดีที่สุดในกรณีที่มีหลายเธรด

จุดด้อย: การเข้าชมที่มีประสิทธิภาพทำให้การดำเนินการช้าลงเล็กน้อย

ไม่ใช่อะตอม:

ซึ่งแตกต่างจากอะตอมมิกมันไม่มั่นใจว่าวัตถุที่ถูกกำหนดค่าเริ่มต้นกลับมาอย่างสมบูรณ์ในแต่ละครั้ง

จุดเด่น: การดำเนินการที่รวดเร็วมาก

จุดด้อย: โอกาสของมูลค่าขยะในกรณีที่มีหลายเธรด


5
ความคิดเห็นนั้นไม่สมเหตุสมผลนัก คุณช่วยอธิบายได้ไหม ถ้าคุณดูตัวอย่างบนไซต์ Apple คำหลักอะตอมมิกซิงโครไนซ์บนวัตถุในขณะที่อัพเดตคุณสมบัติ
Andrew Grant

52

คำตอบที่ง่ายที่สุดก่อน: ไม่มีความแตกต่างระหว่างสองตัวอย่างที่สองของคุณ โดยค่าเริ่มต้น accessors คุณสมบัติเป็นอะตอม

ตัวเข้าถึงอะตอมมิกในสภาพแวดล้อมที่ไม่ได้รวบรวมขยะ (เช่นเมื่อใช้การเก็บรักษา / ปล่อย / การเลิกอัตโนมัติ) จะใช้การล็อกเพื่อให้แน่ใจว่าเธรดอื่นไม่รบกวนการตั้งค่า / การรับค่าที่ถูกต้อง

ดูส่วน " ประสิทธิภาพและเธรด " ของเอกสาร Objective-C 2.0 ของ Apple สำหรับข้อมูลเพิ่มเติมและข้อควรพิจารณาอื่น ๆ เมื่อสร้างแอพแบบมัลติเธรด


8
ด้วยเหตุผลสองประการ ก่อนอื่นสำหรับรหัสที่สังเคราะห์จะสร้างเร็วขึ้น (แต่ไม่ใช่รหัสที่ปลอดภัย) ประการที่สองถ้าคุณกำลังเขียน accessors ของลูกค้าที่ไม่ใช่ atomic นั้นจะช่วยให้คุณใส่คำอธิบายประกอบสำหรับผู้ใช้ในอนาคตว่ารหัสไม่ได้เป็น atomic เมื่อพวกเขาอ่านส่วนต่อประสานของพวกเขาโดยไม่ทำให้พวกเขาดำเนินการ
Louis Gerbarg


31

อะตอมหมายถึงเพียงหนึ่งเธรดเข้าถึงตัวแปร (ชนิดคงที่) อะตอมมีความปลอดภัยต่อเธรด แต่ช้า

Nonatomic หมายถึงหลายเธรดเข้าถึงตัวแปร (ชนิดไดนามิก) Nonatomic เป็นเธรดที่ไม่ปลอดภัย แต่รวดเร็ว


14

อะตอมมิกนั้นมีความปลอดภัยต่อเธรดมันช้าและได้รับการรับรองเป็นอย่างดี (ไม่รับประกัน)ว่าจะให้เฉพาะค่าที่ล็อกเท่านั้นไม่ว่าจะมีเธรดจำนวนเท่าใดที่พยายามเข้าถึงในโซนเดียวกัน เมื่อใช้งานปรมาณูชิ้นส่วนของรหัสที่เขียนภายในฟังก์ชั่นนี้จะกลายเป็นส่วนหนึ่งของส่วนที่สำคัญซึ่งมีเพียงหนึ่งเธรดที่สามารถดำเนินการได้ในแต่ละครั้ง

มันรับประกันความปลอดภัยด้ายเท่านั้น; มันไม่รับประกันว่า สิ่งที่ฉันหมายถึงคือคุณจ้างคนขับรถมืออาชีพสำหรับคุณ แต่ก็ไม่รับประกันว่ารถจะไม่เกิดอุบัติเหตุ อย่างไรก็ตามความน่าจะเป็นยังคงอยู่เพียงเล็กน้อย

ปรมาณู - ไม่สามารถแยกย่อยได้ดังนั้นคาดว่าผลลัพธ์ ด้วย nonatomic - เมื่อเธรดอื่นเข้าถึงโซนหน่วยความจำสามารถแก้ไขได้ดังนั้นผลลัพธ์จึงไม่คาดคิด

รหัสคุย:

Atomic make getter และ setter ของ thread คุณสมบัติปลอดภัย เช่นถ้าคุณได้เขียน:

self.myProperty = value;

ด้ายปลอดภัย

[myArray addObject:@"Abc"] 

ไม่ปลอดภัยสำหรับเธรด


ฉันไม่รู้ว่าย่อหน้าสุดท้ายเกิดขึ้นได้อย่างไร แต่มันก็ผิดง่ายไม่มีสิ่งเช่น "สำเนาส่วนตัว"
สูงสุด

13

ไม่มีคำหลัก "อะตอมมิก" ดังกล่าว

@property(atomic, retain) UITextField *userName;

เราสามารถใช้ข้างต้นเช่น

@property(retain) UITextField *userName;

ดูคำถามกองมากเกินฉันได้รับปัญหาหากผมใช้ @property (อะตอมรักษา) NSString *


10
"มีคำหลักดังกล่าว" ซึ่งคำหลักนั้นไม่จำเป็นต้องมีตามค่าเริ่มต้นและแม้กระทั่งค่าเริ่มต้นก็ไม่ได้หมายความว่าไม่มีคำหลักนั้นอยู่
Matthijn

4
สิ่งนี้ไม่ถูกต้อง คำหลักนั้นมีอยู่ คำตอบนี้ทำให้เข้าใจผิดและฉันอยากจะแนะนำให้ลง
sethfri

12

อะตอม (ค่าเริ่มต้น)

Atomic เป็นค่าเริ่มต้น: ถ้าคุณไม่พิมพ์อะไรเลยทรัพย์สินของคุณคือ atomic คุณสมบัติของอะตอมนั้นรับประกันได้ว่าหากคุณพยายามอ่านมันคุณจะได้รับค่าที่ถูกต้อง มันไม่ได้รับประกันใด ๆ เกี่ยวกับค่าที่อาจเป็น แต่คุณจะได้รับข้อมูลที่ดีไม่ใช่แค่หน่วยความจำขยะ สิ่งนี้ช่วยให้คุณทำคือถ้าคุณมีหลายกระทู้หรือหลายกระบวนการที่ชี้ไปที่ตัวแปรเดียวหนึ่งกระทู้สามารถอ่านและหัวข้ออื่นสามารถเขียน หากมีการเข้าชมพร้อมกันเธรดเครื่องอ่านจะรับประกันว่าจะได้รับหนึ่งในสองค่า: ก่อนการเปลี่ยนแปลงหรือหลังการเปลี่ยนแปลง สิ่งที่อะตอมมิกไม่ให้คุณคือการรับประกันใด ๆ เกี่ยวกับค่าใดที่คุณอาจได้รับ อะตอมมักสับสนกับความปลอดภัยของเธรดและนั่นไม่ถูกต้อง คุณต้องรับประกันความปลอดภัยของเธรดด้วยวิธีอื่น

nonatomic

ในทางกลับกันไม่มีอะตอมในขณะที่คุณอาจเดาได้ว่าหมายถึง“ อย่าทำสิ่งที่เป็นอะตอม” สิ่งที่คุณสูญเสียคือการรับประกันว่าคุณจะได้รับสิ่งคืน หากคุณพยายามอ่านระหว่างการเขียนคุณสามารถเรียกคืนข้อมูลขยะได้ แต่ในทางกลับกันคุณไปเร็วขึ้นเล็กน้อย เนื่องจากคุณสมบัติของอะตอมต้องทำเวทมนต์เพื่อรับประกันว่าคุณจะได้รับค่ากลับมาพวกเขาจึงช้าลงเล็กน้อย หากเป็นคุณสมบัติที่คุณเข้าถึงบ่อยครั้งคุณอาจต้องเลื่อนไปที่ nonatomic เพื่อให้แน่ใจว่าคุณจะไม่ได้รับโทษนั้น

ดูเพิ่มเติมได้ที่นี่: https://realm.io/news/tmi-objective-c-property-attributes/


11

เริ่มต้นเป็นatomicวิธีนี้มันไม่เสียค่าใช้จ่ายประสิทธิภาพการทำงานเมื่อใดก็ตามที่คุณใช้คุณสมบัติ แต่มันมีความปลอดภัยด้าย สิ่งที่ Objective-C ทำคือตั้งค่าการล็อคดังนั้นเฉพาะเธรดที่แท้จริงเท่านั้นที่สามารถเข้าถึงตัวแปรได้ตราบใดที่ setter / getter ถูกเรียกใช้งาน

ตัวอย่างด้วย MRC ของคุณสมบัติที่มี ivar _internal:

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

ดังนั้นสองคนสุดท้ายนี้เหมือนกัน:

@property(atomic, retain) UITextField *userName;

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

ในทางกลับกันจะไม่nonatomicเพิ่มอะไรในรหัสของคุณ ดังนั้นจึงเป็นเรื่องที่ปลอดภัยเท่านั้นถ้าคุณใช้รหัสกลไกความปลอดภัยด้วยตัวเอง

@property(nonatomic, retain) UITextField *userName;

คำหลักไม่จำเป็นต้องเขียนเป็นคุณสมบัติคุณสมบัติแรกเลย

อย่าลืมนี่ไม่ได้หมายความว่าสถานที่ให้บริการโดยรวมจะปลอดภัย เฉพาะการเรียกเมธอดของ setter / getter เท่านั้น แต่ถ้าคุณใช้ setter และหลังจากนั้น getter ในเวลาเดียวกันด้วย 2 เธรดที่แตกต่างกันก็อาจแตกได้เช่นกัน!


10

ก่อนที่คุณจะเริ่ม: คุณต้องรู้ว่าวัตถุทุกอย่างในหน่วยความจำต้องได้รับการจัดสรรคืนจากหน่วยความจำเพื่อให้นักเขียนใหม่เกิดขึ้น คุณไม่เพียงแค่เขียนบนสิ่งที่คุณทำบนกระดาษ คุณต้องลบ (dealloc) ก่อนจากนั้นจึงเขียนลงไป หากในขณะนั้นการลบเสร็จสิ้น (หรือเสร็จแล้วครึ่งหนึ่ง) และยังไม่มีการเขียนอะไรเลย (หรือครึ่งหนึ่งเขียนไว้) และคุณลองอ่านมันอาจเป็นปัญหาได้! Atomic และ nonatomic ช่วยให้คุณแก้ไขปัญหานี้ได้หลายวิธี

ครั้งแรกที่อ่านนี้คำถามแล้วอ่านคำตอบของ Bbum นอกจากนี้แล้วอ่านบทสรุปของฉัน


atomic จะรับประกันเสมอ

  • หากคนสองคนต้องการอ่านและเขียนในเวลาเดียวกันกระดาษของคุณก็จะไม่ไหม้! -> แอปพลิเคชันของคุณจะไม่ผิดพลาดแม้แต่ในสภาพการแข่งขัน
  • หากบุคคลหนึ่งพยายามเขียนและเขียนจดหมายเพียง 4 ฉบับจาก 8 ฉบับเท่านั้นก็จะไม่สามารถอ่านตรงกลางได้การอ่านจะทำได้ก็ต่อเมื่อมีการเขียนจดหมายทั้งหมด 8 ฉบับ -> จะไม่มีการอ่าน (รับ) ที่จะเกิดขึ้น 'เธรดที่ยังคงเขียนอยู่' เช่นหากมี 8 ไบต์ถึงไบต์ที่จะเขียนและมีเพียง 4 ไบต์เท่านั้นที่เขียน - จนถึงขณะนั้นคุณจะไม่ได้รับอนุญาตให้อ่าน แต่เนื่องจากฉันบอกว่ามันจะไม่ผิดพลาดจากนั้นมันก็จะอ่านจากมูลค่าของวัตถุออโต้เซลเลอร์
  • ถ้าก่อนเขียนคุณมีลบสิ่งที่เคยเขียนบนกระดาษแล้วมีคนต้องการอ่านคุณยังสามารถอ่าน อย่างไร? คุณจะอ่านจากสิ่งที่คล้ายกับถังขยะในระบบปฏิบัติการ Mac OS (เนื่องจากถังขยะยังไม่ถูกลบ 100% ... มันอยู่ในบริเวณขอบรก) ---> ถ้า ThreadA กำลังอ่านในขณะที่ ThreadB ยกเลิกการจัดสรรแล้วเพื่อเขียนคุณจะได้รับ ค่าจากทั้งค่าสุดท้ายเขียนโดย ThreadB หรือรับบางสิ่งบางอย่างจากสระว่ายน้ำอัตโนมัติ

จำนวนที่เก็บรักษาเป็นวิธีการจัดการหน่วยความจำใน Objective-C เมื่อคุณสร้างวัตถุนั้นจะมีจำนวนการเก็บรักษา 1 เมื่อคุณส่งวัตถุข้อความเก็บรักษาจำนวนการเก็บรักษานั้นจะเพิ่มขึ้น 1 เมื่อคุณส่งวัตถุข้อความแจ้งข่าวการปล่อยจำนวนการเก็บรักษาของมันจะลดลง 1 เมื่อคุณ ส่งวัตถุและข้อความ autorelease อัตโนมัติจำนวนการเก็บของมันจะลดลง 1 ในบางขั้นตอนในอนาคต หากจำนวนการเก็บรักษาของวัตถุลดลงเป็น 0 จะถูกยกเลิกการจัดสรร

  • อะตอม ไม่ได้รับประกันความปลอดภัยของเธรดแม้ว่าจะมีประโยชน์สำหรับการบรรลุความปลอดภัยของเธรด ความปลอดภัยของเธรดเกี่ยวข้องกับวิธีที่คุณเขียนรหัส / คิวเธรดที่คุณกำลังอ่าน / เขียน มันรับประกันว่าไม่มีเธรดมัลติเธรดที่ไม่สามารถชนกันได้

อะไร?! มีหลายเธรดและความปลอดภัยของเธรดต่างกันหรือไม่?

ใช่. การมัลติเธรดหมายถึง: หลายเธรดสามารถอ่านข้อมูลที่ใช้ร่วมกันในเวลาเดียวกันและเราจะไม่ผิดพลาด แต่ก็ไม่รับประกันว่าคุณจะไม่ได้อ่านจากค่าที่ไม่ใช่ระบบอัตโนมัติ ด้วยความปลอดภัยของเธรดจึงรับประกันได้ว่าสิ่งที่คุณอ่านไม่ได้เปิดตัวโดยอัตโนมัติ เหตุผลที่เราไม่ได้ทำทุกอย่างเป็นค่าเริ่มต้นคือค่าใช้จ่ายด้านประสิทธิภาพและส่วนใหญ่ไม่ต้องการความปลอดภัยของเธรด บางส่วนของรหัสของเราต้องการมันและสำหรับบางส่วนนั้นเราต้องเขียนโค้ดของเราด้วยวิธีที่ปลอดภัยต่อการใช้ล็อคล็อค mutex หรือการซิงโครไนซ์


nonatomic

  • เนื่องจากไม่มีสิ่งเช่น Mac OS Trash Bin ดังนั้นจึงไม่มีใครสนใจว่าคุณจะได้รับคุณค่าเสมอหรือไม่ (<- สิ่งนี้อาจนำไปสู่การล่มสลาย) หรือใครก็ตามที่สนใจถ้ามีคนพยายามอ่านครึ่งทางผ่านการเขียนของคุณ การเขียนลงครึ่งหนึ่งในหน่วยความจำจะแตกต่างจากการเขียนลงครึ่งหนึ่งบนกระดาษในหน่วยความจำมันอาจทำให้คุณมีค่าบ้า ๆ บอ ๆ จากก่อนหน้านี้ในขณะที่บนกระดาษคุณเห็นเพียงครึ่งหนึ่งของสิ่งที่เขียน) -> ไม่รับประกันว่า ไม่ใช้กลไกการยกเลิกอัตโนมัติ
  • ไม่รับประกันว่าจะอ่านค่าที่เขียนทั้งหมด!
  • เร็วกว่าอะตอม

โดยรวมแล้วพวกเขาแตกต่างกันใน 2 ด้าน:

  • ล้มเหลวหรือไม่เนื่องจากการมีหรือไม่มีสระว่ายน้ำอัตโนมัติ

  • ช่วยให้ได้รับสิทธิในการอ่านในช่วงกลางของ 'ยังไม่ได้เขียนสำเร็จรูปหรือค่าว่าง' หรือไม่อนุญาตให้และมีเพียงช่วยให้การอ่านเมื่อค่าเป็นอย่างเต็มที่เขียน


9

หากคุณใช้คุณสมบัติของคุณในรหัสแบบมัลติเธรดคุณจะสามารถเห็นความแตกต่างระหว่างแอตทริบิวต์ที่ไม่ใช่แบบอะตอมมิกและอะตอมมิก Nonatomic เร็วกว่าอะตอมมิกและอะตอมเป็น thread-safe ไม่ใช่ nonatomic

Vijayendra Tripathi ได้ให้ตัวอย่างไว้แล้วสำหรับสภาพแวดล้อมแบบมัลติเธรด


9
  • -Atomic หมายถึงเพียงเธรดเดียวที่เข้าถึงตัวแปร (ชนิดสแตติก)
  • - อะตอมเป็นเธรดที่ปลอดภัย
  • - แต่มันช้าในประสิทธิภาพ

ประกาศอย่างไร:

เนื่องจากอะตอมเป็นค่าเริ่มต้นดังนั้น

@property (retain) NSString *name;

และในไฟล์การใช้งาน

self.name = @"sourov";

สมมติว่างานที่เกี่ยวข้องกับคุณสมบัติสามประการคือ

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

คุณสมบัติทั้งหมดทำงานคู่ขนาน (เช่นแบบอะซิงโครนัส)

ถ้าคุณเรียกว่า "ชื่อ" จากหัวข้อ,

และ

ในเวลาเดียวกันถ้าคุณโทร

[self setName:@"Datta"]

จากหัวข้อB ,

ตอนนี้ถ้าคุณสมบัติของชื่อ * ไม่ใช่เชิงอะตอมแล้ว

  • มันจะคืนค่า "Datta" สำหรับ A
  • มันจะคืนค่า "Datta" สำหรับ B

นั่นเป็นสาเหตุที่ไม่ใช่อะตอมที่เรียกว่าเธรดที่ไม่ปลอดภัย แต่มันมีประสิทธิภาพในการทำงานที่รวดเร็วเนื่องจากมีการประมวลผลแบบขนาน

ตอนนี้ถ้าคุณสมบัติ name คือ atomic

  • มันจะรับรองคุณค่า "Sourov" สำหรับ A
  • จากนั้นจะส่งคืนค่า "Datta" สำหรับ B

นั่นคือเหตุผลที่อะตอมเรียกว่า thread safeและ นั่นคือสาเหตุที่เรียกว่า safe-read safe

การดำเนินการตามสถานการณ์ดังกล่าวจะดำเนินการตามลำดับ และประสิทธิภาพลดลง

- Nonatomic หมายถึงการเข้าถึงตัวแปรหลายเธรด (ชนิดไดนามิก)

- Nonatomic เป็นเธรดที่ไม่ปลอดภัย

- แต่ประสิทธิภาพก็รวดเร็ว

-Nonatomic ไม่ใช่พฤติกรรมเริ่มต้นเราจำเป็นต้องเพิ่มคำหลักที่ไม่ใช่เชิงอะตอมในคุณสมบัติของคุณสมบัติ

สำหรับ In Swift ยืนยันว่าคุณสมบัติของ Swift ไม่ใช่แบบเชิงอะตอมในความหมายของ ObjC เหตุผลหนึ่งคือให้คุณคิดว่าอะตอมต่อคุณสมบัตินั้นเพียงพอสำหรับความต้องการของคุณหรือไม่

การอ้างอิง: https://forums.developer.apple.com/thread/25642

สำหรับข้อมูลเพิ่มเติมโปรดเยี่ยมชมเว็บไซต์ http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html


4
เป็นจำนวนมากหลาย maaaaany อื่น ๆ อีกมากมายได้กล่าวว่าatomicจะไม่ด้ายปลอดภัย! มันทนต่อปัญหาของเธรดได้มากกว่า แต่ไม่ปลอดภัยต่อเธรด เป็นเพียงการรับรองว่าคุณจะได้รับค่าทั้งหมดหรือที่รู้จักว่า "ถูกต้อง" (ระดับไบนารี) แต่ไม่ได้หมายความว่าจะมั่นใจได้ว่ามันเป็นค่าปัจจุบันและ "ถูกต้อง" สำหรับตรรกะทางธุรกิจของคุณ (อาจเป็นค่าในอดีตและ ตรรกะของคุณไม่ถูกต้อง)
Alejandro Iván

6

อะตอมมิกอะตอม (ค่าเริ่มต้น)

Atomic เป็นค่าเริ่มต้น: ถ้าคุณไม่พิมพ์อะไรเลยทรัพย์สินของคุณคือ atomic คุณสมบัติของอะตอมนั้นรับประกันได้ว่าหากคุณพยายามอ่านมันคุณจะได้รับค่าที่ถูกต้อง มันไม่ได้รับประกันใด ๆ เกี่ยวกับค่าที่อาจเป็น แต่คุณจะได้รับข้อมูลที่ดีไม่ใช่แค่หน่วยความจำขยะ สิ่งนี้ช่วยให้คุณทำคือถ้าคุณมีหลายกระทู้หรือหลายกระบวนการที่ชี้ไปที่ตัวแปรเดียวหนึ่งกระทู้สามารถอ่านและหัวข้ออื่นสามารถเขียน หากมีการเข้าชมพร้อมกันเธรดเครื่องอ่านจะรับประกันว่าจะได้รับหนึ่งในสองค่า: ก่อนการเปลี่ยนแปลงหรือหลังการเปลี่ยนแปลง สิ่งที่อะตอมมิกไม่ให้คุณคือการรับประกันใด ๆ เกี่ยวกับค่าใดที่คุณอาจได้รับ อะตอมมักสับสนกับความปลอดภัยของเธรดและนั่นไม่ถูกต้อง คุณต้องรับประกันความปลอดภัยของเธรดด้วยวิธีอื่น

nonatomic

ในทางกลับกันไม่มีอะตอมในขณะที่คุณอาจเดาได้ว่าหมายถึง“ อย่าทำสิ่งที่เป็นอะตอม” สิ่งที่คุณสูญเสียคือการรับประกันว่าคุณจะได้รับสิ่งคืน หากคุณพยายามอ่านระหว่างการเขียนคุณสามารถเรียกคืนข้อมูลขยะได้ แต่ในทางกลับกันคุณไปเร็วขึ้นเล็กน้อย เนื่องจากคุณสมบัติของอะตอมต้องทำเวทมนต์เพื่อรับประกันว่าคุณจะได้รับค่ากลับมาพวกเขาจึงช้าลงเล็กน้อย หากเป็นคุณสมบัติที่คุณเข้าถึงบ่อยครั้งคุณอาจต้องเลื่อนไปที่ nonatomic เพื่อให้แน่ใจว่าคุณจะไม่ได้รับโทษนั้น เข้าไป

มารยาทhttps://academy.realm.io/posts/tmi-objective-c-property-attributes/

แอ็ตทริบิวต์คุณสมบัติ Atomicity (atomic และ nonatomic) ไม่ได้สะท้อนให้เห็นในการประกาศคุณสมบัติ Swift ที่สอดคล้องกัน แต่การรับประกันอะตอมมิกซิตี้ของการใช้งาน Objective-C ยังคงมีอยู่เมื่อเข้าถึงคุณสมบัติที่นำเข้าจาก Swift

ดังนั้น - ถ้าคุณกำหนดคุณสมบัติอะตอมมิกใน Objective-C มันจะยังคงเป็นอะตอมมิกเมื่อใช้โดย Swift

มารยาท https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c


5

คุณสมบัติของอะตอมช่วยให้มั่นใจว่าจะสามารถรักษาค่าเริ่มต้นได้อย่างเต็มที่โดยไม่คำนึงถึงว่ามีเธรดจำนวนเท่าใดที่ได้รับตัวตั้งค่าและตัวตั้งบน

คุณสมบัติ nonatomic ระบุว่าการสังเคราะห์ accessors เพียงแค่ตั้งค่าหรือคืนค่าโดยตรงโดยไม่รับประกันว่าจะเกิดอะไรขึ้นถ้าค่าเดียวกันนั้นถูกเข้าถึงพร้อมกันจากเธรดที่แตกต่างกัน


3

Atomic หมายถึงเพียงเธรดเดียวเท่านั้นที่สามารถเข้าถึงตัวแปรในแต่ละครั้ง (ชนิดคงที่) อะตอมมีความปลอดภัยต่อเธรด แต่ช้า

Nonatomic หมายถึงหลายเธรดสามารถเข้าถึงตัวแปรในเวลาเดียวกัน (ชนิดไดนามิก) Nonatomic เป็นเธรดที่ไม่ปลอดภัย แต่รวดเร็ว


1

หากคุณกำลังใช้อะตอมมิกนั่นหมายความว่าเธรดจะปลอดภัยและอ่านได้อย่างเดียว หากคุณใช้ nonatomic หมายถึงหลายเธรดเข้าถึงตัวแปรและเป็นเธรดที่ไม่ปลอดภัย แต่ถูกเรียกใช้อย่างรวดเร็วทำการอ่านและเขียน นี่คือประเภทแบบไดนามิก


1

ความจริงก็คือพวกเขาใช้สปินล็อคเพื่อใช้คุณสมบัติอะตอมมิก รหัสดังต่อไปนี้:

 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);
    }

0

เพื่อลดความสับสนให้เราเข้าใจการล็อค mutex

Mutex lock ตามชื่อล็อคความไม่แน่นอนของวัตถุ ดังนั้นถ้าวัตถุถูกเข้าถึงโดยคลาสไม่มีคลาสอื่นสามารถเข้าถึงวัตถุเดียวกันได้

ใน iOS @sychroniseยังมีการล็อก mutex ขณะนี้มันทำหน้าที่ในโหมด FIFO และทำให้แน่ใจว่าการไหลจะไม่ได้รับผลกระทบจากสองคลาสที่แชร์อินสแตนซ์เดียวกัน อย่างไรก็ตามหากงานอยู่ในเธรดหลักให้หลีกเลี่ยงการเข้าถึงออบเจ็กต์โดยใช้คุณสมบัติอะตอมมิกเพราะอาจเก็บ UI ของคุณและลดประสิทธิภาพลง


-1

Atomic: สร้างความมั่นใจในความปลอดภัยของด้ายโดยล็อคเกลียวโดยใช้ NSLOCK

ไม่ใช่อะตอมมิก: ไม่รับประกันความปลอดภัยของเธรดเนื่องจากไม่มีกลไกการล็อกเธรด


-1

คุณสมบัติอะตอมมิก : - เมื่อตัวแปรที่กำหนดด้วยคุณสมบัติอะตอมนั่นหมายความว่ามีการเข้าถึงเธรดเพียงครั้งเดียวและมันจะปลอดภัยต่อเธรดและจะดีในมุมมองประสิทธิภาพจะมีพฤติกรรมเริ่มต้น

คุณสมบัติที่ไม่ใช่อะตอมมิก : - เมื่อตัวแปรที่กำหนดด้วยคุณสมบัติอะตอมซึ่งหมายความว่ามีการเข้าถึงหลายเธรดและจะไม่เป็นเธรดที่ปลอดภัยและจะช้าในมุมมองของประสิทธิภาพการทำงานจะมีพฤติกรรมเริ่มต้นและเมื่อสองเธรดที่แตกต่างกันต้องการเข้าถึงตัวแปรในเวลาเดียวกัน มันจะให้ผลลัพธ์ที่ไม่คาดคิด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.