Clojure ความแตกต่างระหว่าง Ref, Var, Agent, Atom พร้อมตัวอย่าง


110

ฉันใหม่มากสำหรับ Clojure พวกคุณช่วยอธิบายสถานการณ์ในโลกแห่งความจริงให้ฉันได้ไหม ฉันหมายถึงที่ที่จะใช้ Ref, Var, Agent, Atom ฉันอ่านหนังสือ แต่ยังไม่เข้าใจตัวอย่างในโลกแห่งความเป็นจริง

คำตอบ:


174

ฉันขอแนะนำ "The Joy of Clojure" หรือ "Programming Clojure" สำหรับคำตอบที่แท้จริงสำหรับคำถามนี้ฉันสามารถสร้างแรงจูงใจสั้น ๆ ของแต่ละข้อได้ดังนี้

เริ่มต้นด้วยการดูวิดีโอนี้ในความคิดของรหัสประจำตัวและ / หรือการศึกษาที่นี่

  • การอ้างอิงใช้สำหรับการเข้าถึง "ตัวตนจำนวนมาก" แบบซิงโครนั
  • อะตอมมีไว้สำหรับการเข้าถึงแบบซิงโครนัสแบบ Uncoordinatedไปยัง Identity เดียว
  • ตัวแทนมีไว้สำหรับการเข้าถึงแบบอะซิงโครนัสแบบไม่ประสานกันไปยังข้อมูลประจำตัวเดียว
  • Vars ใช้สำหรับเธรดข้อมูลประจำตัวที่แยกในโลคัลที่มีค่าดีฟอลต์ที่ใช้ร่วมกัน

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

การเข้าถึงแบบไม่ประสานกันจะใช้เมื่อต้องอัปเดต Identity เพียงตัวเดียวซึ่งเป็นกรณีที่พบบ่อยมาก

การเข้าถึงแบบซิงโครนัสถูกใช้เมื่อคาดว่าการโทรจะรอจนกว่าข้อมูลประจำตัวทั้งหมดจะตกลงก่อนดำเนินการต่อ

การเข้าถึงแบบอะซิงโครนัสคือ "จุดไฟและลืม" และปล่อยให้ข้อมูลประจำตัวไปถึงสถานะใหม่ในเวลาของตัวเอง


ในการเข้าถึงแบบประสานงานหากฉันต้องการเปลี่ยนแปลงเท่านั้นstate-aแต่อ้างถึงstate-bในการดำเนินการดังกล่าวฉันยังต้องการความrefถูกต้องหรือไม่? ดังนั้นจึงไม่ได้เปลี่ยนหลายสิ่ง แต่หมายถึงหลายสิ่งในขณะที่เปลี่ยนสิ่งเหล่านี้หรือไม่?
event_jr

2
ใช่ดูเหมือนคุณจะเข้าใจอย่างถูกต้องว่า state-a และ state-b ต้องอ้างอิงทั้งคู่ถ้าคุณต้องการให้ค่าใหม่ใน state-a เป็นไปตามการผสมที่สอดคล้องกันของค่าใน a และ b คุณต้องมีการคำนวณค่าใหม่นั้นในบริบทที่ state-a และ state-b ซึ่งสอดคล้องกับแต่ละค่า เมื่อทั้งคู่เป็น refs ทั้งคู่ถ้า b เปลี่ยนกลางคันธุรกรรมจะรีสตาร์ทและใช้ค่าใหม่ของทั้ง a และ b พิจารณาใช้ensureฟังก์ชัน: clojure.github.io/clojure/clojure.core-api.html#clojure.core/…เพื่อทำให้สิ่งนี้ชัดเจนและมีประสิทธิภาพมากขึ้น
Arthur Ulfeldt

3
อาจมีการเพิ่มคำอธิบายเกี่ยวกับสิ่งที่แยกด้วยค่าเริ่มต้นที่ใช้ร่วมกันเพื่อให้คำตอบสมบูรณ์?
Didier A.

1
"การเข้าถึงพิกัดถูกใช้เมื่อต้องมีการเปลี่ยนแปลงข้อมูลประจำตัวสองตัวพร้อมกัน ... " สิ่งนั้นควร "เปลี่ยนแปลง" หรือไม่?
Carcigenicate

40

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

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

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

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

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


32

เมื่อฉันอ่านเกี่ยวกับประเภทเหล่านี้เป็นครั้งแรกฉันก็พยายามที่จะเข้าใจว่าฉันสามารถหรือควรใช้แต่ละประเภทได้ที่ไหนดังนั้นนี่คือคำตอบภาษาอังกฤษธรรมดาของฉัน:

ใช้ var เมื่อข้อมูลไม่เปลี่ยนแปลง เรื่องนี้เกิดขึ้นเมื่อใดก็ตามที่คุณใช้defหรือฟังก์ชั่นมากที่สุดที่เริ่มต้นด้วยเช่นdefdefn

ใช้อะตอมเมื่อคุณมีรายการเดียวที่เปลี่ยนแปลง ตัวอย่างอาจเป็นตัวนับหรือเวกเตอร์ที่คุณต้องการเพิ่มรายการ

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

ใช้ตัวแทนเมื่อคุณต้องการเปลี่ยนแปลงบางอย่าง แต่คุณไม่สนใจว่าเมื่อไร นี่อาจเป็นการคำนวณที่ยาวนานหรือเขียนบางอย่างลงในไฟล์หรือซ็อกเก็ต โปรดทราบว่าคุณควรใช้send-offหลัง

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


1
ขอบคุณมากสำหรับคำตอบที่ชัดเจนของคุณ :-) ช่วยให้มือใหม่อย่างฉันได้มากทีเดียว
gosukiwi

27

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

Share state - เมื่อใช้ vars, atoms, agent และ refs?

ฉันหวังว่ามันจะช่วยให้ผู้ที่กำลังมองหาคำตอบในหัวข้อนั้น

ทางลัดบางส่วนจากบทความหลังคำแนะนำ @tunaci:

Vars

Vars เป็นแบบสากลสำหรับทุกเธรด

อย่าเปลี่ยน vars หลังจากสร้าง เป็นไปได้ในทางเทคนิค แต่เป็นความคิดที่ไม่ดีด้วยเหตุผลหลายประการ

อะตอม

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

อย่าใช้ฟังก์ชันและฟังก์ชันที่ไม่ได้ใช้งานที่มีการดำเนินการเป็นเวลานาน

ตัวแทน

แบ่งปันการเข้าถึงสถานะที่ไม่แน่นอนสำหรับทุกเธรด การเปลี่ยนแปลงเกิดขึ้นแบบอะซิงโครนัส

อ้างอิง

Refs ทำงานคล้ายกับธุรกรรมฐานข้อมูล การเขียนและการอ่านได้รับการปกป้องใน dosync คุณสามารถดำเนินการกับผู้อ้างอิงจำนวนมากที่ปลอดภัยในการทำธุรกรรม

และผังงานเมื่อใช้อันใด: ผังงาน

โปรดดูภาพบนเว็บไซต์เนื่องจากการอัปเดตบางอย่างสามารถทำได้ตลอดเวลา

มันซับซ้อนและเป็นหัวข้อที่ยาวในการให้คำตอบโดยไม่ต้องคัดลอกและบทความที่ผ่านมาดังนั้นโปรดยกโทษให้ฉันด้วยฉันเปลี่ยนเส้นทางคุณไปที่เว็บไซต์ :)


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