ทับทิมมีมัลติเธรดจริงหรือไม่?


295

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

คำตอบ:


612

อัปเดตด้วยความคิดเห็นของJörgในเดือนกันยายน 2554

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

(น่าเสียดายที่มีเพียง 11 การติดตั้ง 11 ตัวเท่านั้นที่พร้อมใช้งานจริง แต่ภายในสิ้นปีนี้ตัวเลขอาจสูงถึงสี่หรือห้า) ( อัปเดต : ตอนนี้เป็น 5: MRI, JRuby, YARV (ล่าม สำหรับ Ruby 1.9), Rubinius และ IronRuby)

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

    บางครั้งมันก็เรียกว่า "MRI" (สำหรับ "การใช้ทับทิมของ Matz"), CRuby หรือ MatzRuby

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

    อย่างไรก็ตามจำนวนเธรด C ใด ๆ (POSIX เธรด ฯลฯ ) สามารถทำงานแบบขนานกับเธรดทับทิมดังนั้นไลบรารี C ภายนอกหรือส่วนขยาย MRI C ที่สร้างเธรดของตนเองยังสามารถทำงานแบบขนานได้

  2. การใช้งานที่สองคือYARV (ย่อมาจาก "Yet Another Ruby VM") YARV ใช้ Ruby Threads เป็น POSIX หรือเธรด Windows NTอย่างไรก็ตามมันใช้ Global Interpreter Lock (GIL) เพื่อให้แน่ใจว่ามีเพียงหนึ่ง Ruby Thread เท่านั้นที่สามารถกำหนดเวลาจริงได้ในเวลาใดก็ได้

    เช่นเดียวกับ MRI C Threads สามารถรันขนานกับ Ruby Threads ได้

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

  3. JRuby ใช้ Ruby Threads เป็น Native Threadsโดยที่ "Native Threads" ในกรณีของ JVM นั้นหมายถึง "JVM Threads" อย่างชัดเจน JRuby ไม่มีการล็อคเพิ่มเติม ดังนั้นไม่ว่าเธรดเหล่านั้นสามารถรันในแบบขนานจริงหรือไม่ขึ้นอยู่กับ JVM: JVM บางอันใช้ JVM Threads เป็น OS Threads และบางเธรดเป็น Green Threads (JVM หลักจาก Sun / Oracle ใช้เธรด OS เฉพาะตั้งแต่ JDK 1.3)

  4. XRubyยังดำเนินรูบีหัวข้อเป็น JVM กระทู้ อัปเดต : XRuby ตายแล้ว

  5. IronRuby ใช้ Ruby Threads เป็น Native Threadsโดยที่ "Native Threads" ในกรณีของ CLR อย่างชัดเจนหมายถึง "CLR Threads" IronRuby กำหนดให้ไม่มีการล็อคเพิ่มเติมดังนั้นจึงควรรันแบบขนานตราบใดที่ CLR ของคุณรองรับ

  6. Ruby.NETยังดำเนินรูบีหัวข้อเป็น CLR กระทู้ อัพเดต: Ruby.NET ตายแล้ว

  7. Rubinius ดำเนินทับทิมด้ายสีเขียวกระทู้ภายในของเครื่องเสมือน อีกอย่างแม่นยำที่: Rubinius VM ส่งออกที่มีน้ำหนักเบามากมีความยืดหยุ่นมากเห็นพ้อง / ขนาน / นอกท้องถิ่นสร้างการควบคุมการไหลที่เรียกว่า " งาน " และทุกโครงสร้างอื่น ๆ พร้อมกัน (หัวข้อในการสนทนานี้ แต่ยัง , นักแสดงและสิ่งอื่น ๆ ) มีการใช้งานในทับทิมบริสุทธิ์โดยใช้งาน

    (ปัจจุบัน) Rubinius ไม่สามารถกำหนดเวลาเธรดในแบบขนานได้อย่างไรก็ตามการเพิ่มที่ไม่ได้มีปัญหามากเกินไป: Rubinius สามารถรันอินสแตนซ์ VM หลายอินสแตนซ์ใน POSIX Threads หลายขนานพร้อมกันภายในกระบวนการ Rubinius เดียว เนื่องจากเธรดถูกนำไปใช้จริงใน Ruby พวกเขาสามารถเหมือนกับวัตถุ Ruby อื่น ๆ ที่ถูกทำให้เป็นอนุกรมและส่งไปยัง VM ที่แตกต่างกันใน POSIX Thread ที่แตกต่างกัน (นั่นเป็นรูปแบบเดียวกันกับที่ BEAM Erlang VM ใช้สำหรับการทำงานพร้อมกันของ SMP ซึ่งได้นำไปใช้กับ Rubinius Actorsแล้ว)

    อัปเดต : ข้อมูลเกี่ยวกับ Rubinius ในคำตอบนี้เป็นเรื่องเกี่ยวกับ Shotgun VM ซึ่งไม่มีอยู่อีกต่อไป "ใหม่" C ++ VM ไม่ได้ใช้เธรดสีเขียวที่กำหนดไว้ในหลาย VM (เช่นรูปแบบ Erlang / BEAM) มันใช้ VM เดี่ยวแบบดั้งเดิมที่มีรูปแบบเธรด OS แบบดั้งเดิมหลายตัวเช่นเดียวกับที่ใช้โดย CLR, Mono และเกือบทุก JVM

  8. MacRubyเริ่มต้นจากการเป็นพอร์ตของ YARV ด้านบนของ Objective-C Runtime และ CoreFoundation และ Cocoa Frameworks ก็มีตอนนี้แยกออกมาอย่างมีนัยสำคัญจาก YARV แต่ AFAIK มันขณะนี้ยังคงถือหุ้นเดียวกัน Threading รุ่นกับ YARV อัปเดต: MacRuby ขึ้นอยู่กับตัวรวบรวมขยะของแอปเปิ้ลซึ่งประกาศเลิกใช้แล้วและจะถูกลบออกใน MacOSX รุ่นที่ใหม่กว่า MacRuby นั้นไม่ตาย

  9. พระคาร์ดินัลเป็นการนำทับทิมสำหรับเครื่องเสมือนนกแก้ว มันไม่ได้ดำเนินการตามหัวข้อเลย แต่เมื่อมันไม่ก็อาจจะใช้พวกเขาเป็นนกแก้วกระทู้ อัปเดต : ดูเหมือนว่าคาร์ดินัลจะไม่ทำงาน / ตายมาก

  10. MagLevเป็นการนำทับทิมสำหรับอัญมณี / S สมอลล์ทอล์ค VM ฉันไม่มีข้อมูลว่าเกลียวรุ่น GemStone / S ใช้อะไรแบบจำลองเธรดที่ MagLev ใช้หรือแม้ว่าเธรดยังถูกใช้งาน (อาจไม่ใช่)

  11. HotRubyคือไม่ได้ดำเนินการเต็มรูปแบบของทับทิมของตัวเอง มันเป็นการใช้งานของ YARV bytecode VM ใน JavaScript HotRuby ไม่รองรับเธรด (และ?) และเมื่อเป็นเช่นนั้นจะไม่สามารถทำงานแบบขนานได้เนื่องจาก JavaScript ไม่สนับสนุนการขนานแบบจริง มี HotRuby รุ่น ActionScript และจริง ๆ แล้ว ActionScript อาจรองรับขนานได้ อัปเดต : HotRuby ตายแล้ว

น่าเสียดายที่การใช้งานทับทิมเพียงสองใน 11 รายการนี้พร้อมใช้งานจริง: MRI และ JRuby

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

มิฉะนั้นโซลูชันทับทิม "คลาสสิค" คือการใช้กระบวนการแทนเธรดสำหรับการขนาน Ruby Core Library มีProcessโมดูลที่มีProcess.fork วิธีการซึ่งทำให้ง่ายต่อการแยกกระบวนการ Ruby อื่นออก นอกจากนี้ Ruby Standard Library ยังมีไลบรารี Distributed Ruby (dRuby / dRb)ซึ่งอนุญาตให้โค้ด Ruby ถูกแจกจ่ายอย่างไม่น่าเชื่อในหลาย ๆ กระบวนการไม่เพียง แต่ในเครื่องเดียวกัน แต่ยังข้ามเครือข่าย


1
แต่การใช้ fork จะทำให้การใช้งานของ jruby แย่ลง ... แค่พูดว่า
akostadinov

1
นี่คือคำตอบที่ดี อย่างไรก็ตามมันอาจมีการเชื่อมโยงที่เน่ามาก ฉันไม่รู้ว่าแหล่งข้อมูลเหล่านี้อาจย้ายไปอยู่ที่ไหน
BlackVegetable

28

Ruby 1.8 เท่านั้นที่มีเธรดสีเขียวไม่มีวิธีสร้างเธรด "OS-level" จริง แต่ทับทิม 1.9 จะมีคุณสมบัติใหม่ที่เรียกว่าเส้นใยซึ่งจะช่วยให้คุณสร้างเธรดระดับ OS จริง น่าเสียดายที่ Ruby 1.9 ยังอยู่ในช่วงเบต้าซึ่งมีกำหนดจะคงตัวในอีกไม่กี่เดือนข้างหน้า

อีกทางเลือกหนึ่งคือการใช้ JRuby JRuby ใช้เธรดเป็นเธรดระดับ OS, ไม่มี "เธรดสีเขียว" อยู่ในนั้น JRuby เวอร์ชันล่าสุดคือ 1.1.4 และเทียบเท่ากับ Ruby 1.8


35
มันเป็นเรื่องจริงที่ Ruby 1.8 มีเพียงเธรดสีเขียวการใช้งานหลายอย่างของ Ruby 1.8 มีเธรดดั้งเดิม: JRuby, XRuby, Ruby.NET และ IronRuby เส้นใยไม่อนุญาตให้มีการสร้างเธรดแบบดั้งเดิม แต่จะมีน้ำหนักเบากว่าเธรด จริงๆแล้วพวกมันคือกึ่งคอรัลคือพวกมันเป็นสหกรณ์
Jörg W Mittag

19
ฉันคิดว่ามันชัดเจนมากจากคำตอบของ Josh ว่าเขาหมายถึง Ruby 1.8 รันไทม์หรือที่รู้จักในนาม MRI ไม่ใช่ Ruby 1.8 ภาษาเมื่อเขาพูดว่า Ruby 1.8
Theo

@Theo มันชัดเจนว่าเขาสับสนแนวคิดในคำตอบของเขา เส้นใยไม่ได้เป็นวิธีในการสร้างเธรดดั้งเดิมดังที่กล่าวไปแล้วเส้นใยเหล่านั้นมีน้ำหนักเบากว่าเธรดและ cruby ปัจจุบันมีเธรดดั้งเดิม แต่มี GIL
สวนสัตว์ Foo Bar Zoo

8

มันขึ้นอยู่กับการใช้งาน:

  • MRI ไม่มี YARV อยู่ใกล้
  • JRuby และ MacRuby มี




ทับทิมมีการปิดเป็นBlocks, และlambdas Procsเพื่อใช้ประโยชน์อย่างเต็มที่จากการปิดและหลายคอร์ใน JRuby ผู้บริหารของ Javaมีประโยชน์ สำหรับ MacRuby ฉันเหมือนคิว GCD ของ

โปรดทราบว่าการสามารถสร้างเธรด "OS-level" จริงไม่ได้หมายความว่าคุณสามารถใช้หลายแกนประมวลผลแบบขนานสำหรับการประมวลผลแบบขนาน ดูตัวอย่างด้านล่าง

นี่คือผลลัพธ์ของโปรแกรม Ruby แบบง่ายซึ่งใช้ 3 เธรดโดยใช้ Ruby 2.1.0:

(jalcazar@mac ~)$ ps -M 69877
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 69877 s002    0.0 S    31T   0:00.01   0:00.04 /Users/jalcazar/.rvm/rubies/ruby-2.1.0/bin/ruby threads.rb
   69877         0.0 S    31T   0:00.01   0:00.00 
   69877        33.4 S    31T   0:00.01   0:08.73 
   69877        43.1 S    31T   0:00.01   0:08.73 
   69877        22.8 R    31T   0:00.01   0:08.65 

อย่างที่คุณเห็นในที่นี้มีเธรด OS สี่เธรด แต่มีเธรดเดียวเท่านั้นที่Rทำงานอยู่ นี่เป็นเพราะข้อ จำกัด ในการใช้งานเธรดของรูบี้



โปรแกรมเดียวกันตอนนี้พร้อม JRuby คุณสามารถดูสามกระทู้พร้อมสถานะRซึ่งหมายความว่าพวกเขากำลังทำงานแบบคู่ขนาน

(jalcazar@mac ~)$ ps -M 72286
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 72286 s002    0.0 S    31T   0:00.01   0:00.01 /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/bin/java -Djdk.home= -Djruby.home=/Users/jalcazar/.rvm/rubies/jruby-1.7.10 -Djruby.script=jruby -Djruby.shell=/bin/sh -Djffi.boot.library.path=/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jni:/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jni/Darwin -Xss2048k -Dsun.java.command=org.jruby.Main -cp  -Xbootclasspath/a:/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jruby.jar -Xmx1924M -XX:PermSize=992m -Dfile.encoding=UTF-8 org/jruby/Main threads.rb
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    33T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.09   0:02.34 
   72286         7.9 S    31T   0:00.15   0:04.63 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.04   0:01.68 
   72286         0.0 S    31T   0:00.03   0:01.54 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.01   0:00.01 
   72286         0.0 S    31T   0:00.00   0:00.01 
   72286         0.0 S    31T   0:00.00   0:00.03 
   72286        74.2 R    31T   0:09.21   0:37.73 
   72286        72.4 R    31T   0:09.24   0:37.71 
   72286        74.7 R    31T   0:09.24   0:37.80 


โปรแกรมเดียวกันตอนนี้กับ MacRuby นอกจากนี้ยังมีสามเธรดที่ทำงานพร้อมกัน นี่เป็นเพราะเธรด MacRuby เป็นเธรด POSIX ( เธรด"OS-level" จริง ) และไม่มี GVL

(jalcazar@mac ~)$ ps -M 38293
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 38293 s002    0.0 R     0T   0:00.02   0:00.10 /Users/jalcazar/.rvm/rubies/macruby-0.12/usr/bin/macruby threads.rb
   38293         0.0 S    33T   0:00.00   0:00.00 
   38293       100.0 R    31T   0:00.04   0:21.92 
   38293       100.0 R    31T   0:00.04   0:21.95 
   38293       100.0 R    31T   0:00.04   0:21.99 


อีกครั้งโปรแกรมเดียวกัน แต่ตอนนี้กับ MRI เก่าที่ดี เนื่องจากความจริงที่ว่าการใช้งานนี้ใช้กรีนเธรดมีเธรดเดียวเท่านั้นที่ปรากฏขึ้น

(jalcazar@mac ~)$ ps -M 70032
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 70032 s002  100.0 R    31T   0:00.08   0:26.62 /Users/jalcazar/.rvm/rubies/ruby-1.8.7-p374/bin/ruby threads.rb



หากคุณสนใจ Ruby multi-threading คุณอาจพบว่ารายงานของฉันการดีบักโปรแกรมแบบขนานโดยใช้ fork fork ที่น่าสนใจ
สำหรับภาพรวมทั่วไปของทับทิมภายในทับทิมภายใต้กล้องจุลทรรศน์อ่านที่ดี
นอกจากนี้Ruby Threads และ Global Interpreter Lock ใน Cใน Omniref อธิบายในซอร์สโค้ดเหตุที่เธรด Ruby ไม่ทำงานแบบขนาน


โดย RMI คุณหมายถึง MRI หรือเปล่า
Mayuresh Srivastava

4

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


3

ฉันจะให้ "การตรวจสอบระบบ" ตอบคำถามนี้ ฉันกำลังรันรหัสเดียวกัน (ด้านล่างซึ่งคำนวณจำนวนเฉพาะ) ด้วย 8 Ruby threads ที่ทำงานบนเครื่อง i7 (4 hyperthreaded-core) ในทั้งสองกรณี ... การทำงานครั้งแรกคือ:

jruby 1.5.6 (ruby 1.8.7 patchlevel 249) (2014-02-03 6586) (เซิร์ฟเวอร์ OpenJDK 64- บิต VM 1.7.0_75) [amd64-java]

ประการที่สองคือ:

ruby 2.1.2p95 (2014-05-08) [x86_64-linux-gnu]

ที่น่าสนใจคือ CPU นั้นสูงกว่าสำหรับเธรด JRuby แต่เวลาในการดำเนินการจะสั้นกว่าเล็กน้อยสำหรับ Ruby ที่ตีความแล้ว เป็นการยากที่จะบอกจากกราฟ แต่การรันครั้งที่สอง (ตีความรูบี้) ใช้ซีพียูประมาณ 1/2 (ไม่มีไฮเปอร์เธรด?)

ป้อนคำอธิบายรูปภาพที่นี่

def eratosthenes(n)
  nums = [nil, nil, *2..n]
  (2..Math.sqrt(n)).each do |i|
    (i**2..n).step(i){|m| nums[m] = nil}  if nums[i]
  end
  nums.compact
end

MAX_PRIME=10000000
THREADS=8
threads = []

1.upto(THREADS) do |num|
  puts "Starting thread #{num}"
  threads[num]=Thread.new { eratosthenes MAX_PRIME }
end

1.upto(THREADS) do |num|
    threads[num].join
end

1

หากคุณใช้ MRI คุณสามารถเขียนโค้ดเธรดใน C เป็นส่วนขยายหรือใช้พลอย ruby-inline


1

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

นอกจากนี้หากคุณสนใจในอนาคตของเธรดภายใต้ Ruby คุณอาจพบว่าบทความนี้มีประโยชน์


JRuby เป็นตัวเลือกที่ดี สำหรับการประมวลผลแบบขนานโดยใช้กระบวนการฉันชอบ github.com/grosser/parallel Parallel.map(['a','b','c'], :in_processes=>3){...
user454322


1

เนื่องจากไม่สามารถแก้ไขคำตอบนั้นดังนั้นเพิ่มคำตอบใหม่ที่นี่

Update (2017/05/08)

บทความนี้เก่ามากและข้อมูลไม่ได้ติดตามดอกยาง (2017) ปัจจุบันต่อไปนี้เป็นอาหารเสริมบางส่วน:

  1. โอปอลเป็นคอมไพเลอร์ซอร์สโค้ดของ Ruby to JavaScript นอกจากนี้ยังมีการนำ Corelib ของ Ruby มาใช้เป็นเครื่องมือพัฒนาที่ใช้งานอยู่ในปัจจุบันและมีเฟรมเวิร์ก (frontend) ที่ใช้งานได้ดี และการผลิตพร้อม เนื่องจากฐานบนจาวาสคริปต์มันไม่รองรับเธรดแบบขนาน

  2. trufflerubyเป็นการใช้งานที่มีประสิทธิภาพสูงของภาษาการเขียนโปรแกรม Ruby สร้างขึ้นบน GraalVM โดย Oracle Labs TruffleRuby เป็นทางแยกของ JRuby รวมกับรหัสจากโครงการ Rubinius และยังมีรหัสจากการใช้มาตรฐานของ Ruby, MRI ยังคงพัฒนาอยู่ไม่พร้อมผลิต ทับทิมรุ่นนี้ดูเหมือนว่าเกิดมาเพื่อการแสดงฉันไม่รู้ว่ารองรับเธรดแบบขนานหรือไม่ แต่ฉันคิดว่ามันควรจะเป็น

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