Latest web development tutorials

Ruby Multithreading

Setiap program yang berjalan pada sistem adalah sebuah proses. Setiap proses berisi satu atau lebih benang.

Sebuah thread adalah aliran kontrol program tunggal berurutan, secara bersamaan menjalankan beberapa thread dalam satu program melakukan hal yang berbeda, yang disebut multi-threading.

Ruby, kita dapat dibuat dengan beberapa kelas thread Thread, Ruby benang adalah ringan, dapat menjadi cara yang efisien untuk menerapkan kode paralel.


Membuat thread Ruby

Untuk memulai thread baru, Anda hanya dapat memanggil Thread.new:

# 线程 #1 代码部分
Thread.new {
  # 线程 #2 执行代码
}
# 线程 #1 执行代码

contoh

Contoh berikut menunjukkan bagaimana menggunakan multithreading dalam program Ruby:

#!/usr/bin/ruby

def func1
   i=0
   while i<=2
      puts "func1 at: #{Time.now}"
      sleep(2)
      i=i+1
   end
end

def func2
   j=0
   while j<=2
      puts "func2 at: #{Time.now}"
      sleep(1)
      j=j+1
   end
end

puts "Started At #{Time.now}"
t1=Thread.new{func1()}
t2=Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"

Kode di atas dijalankan sebagai akibat dari:

Started At Wed May 14 08:21:54 -0700 2014
func1 at: Wed May 14 08:21:54 -0700 2014
func2 at: Wed May 14 08:21:54 -0700 2014
func2 at: Wed May 14 08:21:55 -0700 2014
func1 at: Wed May 14 08:21:56 -0700 2014
func2 at: Wed May 14 08:21:56 -0700 2014
func1 at: Wed May 14 08:21:58 -0700 2014
End at Wed May 14 08:22:00 -0700 2014

Siklus benang Hidup

1, membuat thread dapat menggunakan Thread.new, Anda juga dapat menggunakan sintaks Thread.start sama atau Thread.fork tiga cara untuk membuat sebuah thread.

2, membuat sebuah thread tanpa memulai, benang akan dijalankan secara otomatis.

3, kelas Thread mendefinisikan metode untuk memanipulasi benang. Thread blok kode eksekusi Thread.new.

4, blok benang adalah nilai pernyataan terakhir di thread, thread dapat dipanggil oleh metode, jika benang selesai, ia mengembalikan nilai benang, atau tidak mengembalikan nilai sampai thread selesai.

5, metode Thread.current mengembalikan sebuah objek untuk representasi thread saat ini. Metode Thread.main mengembalikan thread utama.

6, metode ini dilakukan oleh benang Thread.Join, metode ini akan menangguhkan thread utama sampai thread saat selesai.


Thread Negara

Thread memiliki lima negara:

Thread Negara Kembali Nilai
executable menjalankan
sedang tidur sedang tidur
berhenti batal
terminasi yang normal palsu
terminasi abnormal terjadi nol

Benang dan menyimpang

Ketika pengecualian benang terjadi, dan tidak ada penyelamatan ditangkap, benang biasanya akan dihentikan tanpa peringatan. Namun, jika benang lain Thread # bergabung karena hubungan telah menunggu thread ini, maka benang menunggu juga akan mengangkat pengecualian yang sama.

begin
  t = Thread.new do
    Thread.pass    # 主线程确实在等join
    raise "unhandled exception"
  end
  t.join
rescue
  p $!  # => "unhandled exception"
end

Gunakan tiga metode berikut, Anda bisa mendapatkan penerjemah untuk mengganggu operasi ketika thread berakhir karena pengecualian.

  • skrip startup menentukan pilihan-d, dan modus operasi debugging.
  • Dengan Thread.abort_on_exception mengatur bendera.
  • Gunakan Thread#abort_on_exception ditentukan benang set bendera.

Bila menggunakan salah satu dari tiga metode yang dijelaskan di atas, seluruh juru akan terganggu.

t = Thread.new { ... }
t.abort_on_exception = true

Thread Sinkronisasi

Di Ruby, menyediakan tiga cara disinkronisasi, yaitu:

1. kelas Mutex mengimplementasikan Thread Sinkronisasi

2. Peraturan transfer data Antrian kelas menerapkan sinkronisasi thread

kontrol sinkronisasi 3. Gunakan ConditionVariable

Dengan Mutex kelas mengimplementasikan Thread Sinkronisasi

Dengan kelas Mutex mengimplementasikan thread kontrol sinkronisasi, jika Anda juga membutuhkan sebuah program variabel jam di beberapa thread, Anda dapat menggunakan kunci untuk mengunci bagian variabel. Kode adalah sebagai berikut:

#!/usr/bin/ruby

require "thread"
puts "Synchronize Thread"

@num=200
@mutex=Mutex.new

def buyTicket(num)
     @mutex.lock
          if @num>=num
               @num=@num-num
               puts "you have successfully bought #{num} tickets"
          else
               puts "sorry,no enough tickets"
          end
     @mutex.unlock
end

ticket1=Thread.new 10 do
     10.times do |value|
     ticketNum=15
     buyTicket(ticketNum)
     sleep 0.01
     end
end

ticket2=Thread.new 10 do
     10.times do |value|
     ticketNum=20
     buyTicket(ticketNum)
     sleep 0.01
     end
end

sleep 1
ticket1.join
ticket2.join

Kode di atas dijalankan sebagai akibat dari:

Synchronize Thread
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets

Selain menggunakan kunci terkunci variabel, Anda juga dapat menggunakan try_lock variabel terkunci, Anda juga dapat menggunakan Mutex.synchronize sinkronisasi akses ke variabel tertentu.

transfer data peraturan kelas Antrian mengimplementasikan Thread Sinkronisasi

kelas antrian yang merupakan dukungan antrian benang, antrian dapat disinkronkan dengan akhir kunjungan. benang yang berbeda dapat menggunakan kelas terpadu, tapi jangan khawatir tentang apakah data dapat disinkronkan dalam antrian ini, selain untuk membatasi penggunaan SizedQueue panjang antrian kelas

kelas SizedQueue bisa sangat nyaman untuk membantu kami mengembangkan aplikasi berulir untuk menyinkronkan, masalah sinkronisasi harus ditambahkan ke antrian panjang, Anda tidak peduli tentang benang.

produsen klasik dan konsumen:

#!/usr/bin/ruby

require "thread"
puts "SizedQuee Test"

queue = Queue.new

producer = Thread.new do
     10.times do |i|
          sleep rand(i) # 让线程睡眠一段时间
          queue << i
          puts "#{i} produced"
     end
end

consumer = Thread.new do
     10.times do |i|
          value = queue.pop
          sleep rand(i/2)
          puts "consumed #{value}"
     end
end

consumer.join

Output Program:

SizedQuee Test
0 produced
1 produced
consumed 0
2 produced
consumed 1
consumed 2
3 produced
consumed 34 produced

consumed 4
5 produced
consumed 5
6 produced
consumed 6
7 produced
consumed 7
8 produced
9 produced
consumed 8
consumed 9

Thread Variabel

Thread dapat memiliki variabel pribadi, benang variabel pribadi benang menulis ketika benang dibuat. Hal ini dapat digunakan dalam lingkup benang, tapi benang tidak dapat dibagi secara eksternal.

Tapi kadang-kadang, variabel lokal benang tidak perlu thread lain atau thread utama untuk mengakses bagaimana melakukan? ruby memungkinkan mereka untuk membuat sebuah thread disediakan oleh nama variabel, benang dipandang sebagai gaya yang serupa tabel hash hash. Berdasarkan [] = ditulis oleh [] membaca data. Kami melihat kode berikut:

#!/usr/bin/ruby

count = 0
arr = []

10.times do |i|
   arr[i] = Thread.new {
      sleep(rand(0)/10.0)
      Thread.current["mycount"] = count
      count += 1
   }
end

arr.each {|t| t.join; print t["mycount"], ", " }
puts "count = #{count}"

Kode di atas dijalankan output:

8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10

The menunggu thread utama untuk pelaksanaan thread anak selesai, dan kemudian output setiap nilai. .


Thread prioritas

prioritas thread adalah faktor utama yang mempengaruhi penjadwalan thread. Faktor-faktor lain termasuk lamanya waktu untuk melakukan CPU-benang penjadwalan paket dan sebagainya.

Anda dapat menggunakan Thread.priority diperoleh prioritas thread dan menggunakan Thread.priority = metode untuk menyesuaikan prioritas thread.

default prioritas Sebuah thread untuk 0. eksekusi lebih cepat dari prioritas yang lebih tinggi.

Sebuah Thread dapat mengakses semua data dalam lingkup mereka sendiri, tetapi jika ada benang lain perlu mengakses data di thread harus bagaimana melakukannya? kelas Thread menyediakan data benang mengakses satu sama lain, Anda hanya dapat menempatkan thread sebagai meja Hash, dapat digunakan dalam setiap thread [] data = Write, gunakan [] membaca data.

athr = Thread.new { Thread.current["name"] = "Thread A"; Thread.stop }
bthr = Thread.new { Thread.current["name"] = "Thread B"; Thread.stop }
cthr = Thread.new { Thread.current["name"] = "Thread C"; Thread.stop }
Thread.list.each {|x| puts "#{x.inspect}: #{x["name"]}" }

Kita bisa melihat, benang sebagai meja Hash, gunakan [] dan [] = metode, kita mencapai berbagi antara benang data.


Thread mutex

Mutex (mutal Exclusion = mutex) adalah metode untuk multi-threaded, mekanisme untuk mencegah dua thread secara bersamaan untuk sumber daya yang sama publik (seperti variabel global) membaca dan menulis.

Contoh non-penggunaan Mutax

#!/usr/bin/ruby
require 'thread'

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      count1 += 1
      count2 += 1
   end
end
spy = Thread.new do
   loop do
      difference += (count1 - count2).abs
   end
end
sleep 1
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

Jalankan contoh di atas output:

count1 :  9712487
count2 :  12501239
difference : 0

Contoh Mutax

#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      mutex.synchronize do
         count1 += 1
         count2 += 1
      end
    end
end
spy = Thread.new do
   loop do
       mutex.synchronize do
          difference += (count1 - count2).abs
       end
   end
end
sleep 1
mutex.lock
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

Jalankan contoh di atas output:

count1 :  1336406
count2 :  1336406
difference : 0

jalan buntu

Lebih dari dua unit operasi, kedua belah pihak sedang menunggu yang lain untuk berhenti berjalan, untuk mendapatkan sumber daya sistem, tetapi bukan partai keluar awal, situasi ini disebut kebuntuan.

Misalnya, proses p1 memakan display, sementara Anda harus menggunakan printer, dan printer ditempati oleh p2 proses, p2 juga harus menggunakan monitor, sehingga membentuk kebuntuan.

Ketika kita menggunakan mutex objek membutuhkan perhatian benang kebuntuan.

contoh

#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

cv = ConditionVariable.new
a = Thread.new {
   mutex.synchronize {
      puts "A: I have critical section, but will wait for cv"
      cv.wait(mutex)
      puts "A: I have critical section again! I rule!"
   }
}

puts "(Later, back at the ranch...)"

b = Thread.new {
   mutex.synchronize {
      puts "B: Now I am critical, but am done with cv"
      cv.signal
      puts "B: I am still critical, finishing up"
   }
}
a.join
b.join

Contoh di atas output:

A: I have critical section, but will wait for cv
(Later, back at the ranch...)
B: Now I am critical, but am done with cv
B: I am still critical, finishing up
A: I have critical section again! I rule!

metode kelas Thread

Thread (benang) metode kelas lengkap sebagai berikut:

Tidak. metode Deskripsi
1 Thread.abort_on_exception
Jika benar, sekali thread berakhir karena pengecualian, seluruh juru akan terganggu. Nilai default adalah palsu, yaitu, dalam keadaan normal, jika pengecualian benang terjadi dan pengecualian tidak Thread # bergabung dan lainnya terdeteksi, benang akan dihentikan tanpa peringatan.
2 Thread.abort_on_exception =
Jika diatur kebenar,sekali thread berakhir karena pengecualian, seluruh juru akan terganggu. Mengembalikan negara baru
3 Thread.critical
Mengembalikan nilai Boolean.
4 Thread.critical =
Ketika nilai benar, benang tidak akan diaktifkan. Jika thread saat untuk menggantung (berhenti) atau sinyal (sinyal) intervensi, nilainya akan secara otomatis berubah ke false.
5 Thread.current
Mengembalikan thread yang sedang berjalan (thread saat).
6 Thread.exit
Ini mengakhiri thread saat ini. Mengembalikan thread saat ini. Jika thread saat ini satu-satunya benang, menggunakan pintu keluar (0) untuk mengakhiri operasinya.
7 Thread.fork {blok}
Seperti dengan Thread.new menghasilkan benang.
8 Thread.kill (aThread)
Mengakhiri thread berjalan.
9 Thread.list
Mengembalikan array benang hidup sedang berjalan atau ditangguhkan negara.
10 Thread.main
Kembali ke thread utama.
11 Thread.new ([arg] *) { | args | blok}
Menghasilkan benang dan mulai eksekusi. Jumlah tersebut akan diteruskan utuh ke blok. Hal ini dapat memulai thread pada saat yang sama, nilai akan diteruskan ke variabel lokal yang melekat dalam benang.
12 Thread.pass
hak untuk menjalankan benang lain. Ini tidak mengubah keadaan benang berjalan, tetapi akan menyerahkan kontrol dari benang lainnya dapat berjalan (Explicit penjadwalan thread).
13 Thread.start ([args] *) { | args | blok}
Menghasilkan benang dan mulai eksekusi. Jumlah tersebut akan diteruskan utuh ke blok. Hal ini dapat memulai thread pada saat yang sama, nilai akan diteruskan ke variabel lokal yang melekat dalam benang.
14 Thread.stop
Thread saat ditangguhkan sampai benang lain metode berlari lagi bangun benang.

metode contoh benang

Contoh berikut memanggil metode benang contoh bergabung:

#!/usr/bin/ruby

thr = Thread.new do   # 实例化
   puts "In second thread"
   raise "Raise exception"
end
thr.join   # 调用实例化方法 join

Berikut adalah daftar lengkap contoh metode:

Tidak. metode Deskripsi
1 thr [nama]
Lepaskan benang nama sesuai dengan data yang melekat. Nama bisa berupa string atau simbol. Jika nama tidak sesuai dengan data, ia mengembalikan nil.
2 thr [nama] =
Mengatur nilai nama benang dalam data karakteristik yang sesuai, nama bisa berupa string atau simbol. Jika nil, menghapus data yang sesuai di thread ini.
3 thr.abort_on_exception
Mengembalikan nilai Boolean.
4 thr.abort_on_exception =
Jika nilainya benar, maka sekali thread berakhir karena pengecualian, seluruh juru akan terganggu.
5 thr.alive?
Jika benang adalah "hidup", ia mengembalikan benar.
6 thr.exit
Mengakhiri thread berjalan. Pengembalian diri.
7 thr.join
Menunda thread saat sampai diri berjalan sampai benang berakhir. Jika diri karena terminasi abnormal, benang saat ini akan memicu pengecualian yang sama.
8 thr.key?
Jika nama yang sesuai dengan data yang melekat telah benang didefinisikan, kemudian kembali benar
9 thr.kill
Thread.exit serupa.
10 thr.priority
Mengembalikan prioritas thread. Prioritas default adalah 0. besar nilai, semakin tinggi prioritas.
11 thr.priority =
Mengatur prioritas thread. Anda juga dapat mengaturnya untuk negatif.
12 thr.raise (anException)
Dalam thread ini paksa dilemparkan.
13 thr.run
Restart Tertunda (berhenti) thread. Perbedaannya adalah bahwa dengan wakeup akan melakukan benang beralih segera. Jika menggunakan metode ini untuk memproses orang mati akan dibangkitkan ThreadError pengecualian.
14 thr.safe_level
Mengembalikan tingkat keamanan diri. Safe_level benang saat ini $ SAFE yang sama.
15 thr.status
Menggunakan string "run", "tidur" atau "batal" untuk menunjukkan status dari benang hidup jika thread dihentikan normal, maka kembali palsu. Ruoyin normal terminasi, maka kembali nihil.
16 thr.stop?
Jika benang diakhiri negara (mati) atau menangguhkan (berhenti), kembali benar.
17 thr.value
Tunggu sampai thread diri berakhir (setara dengan bergabung), kembali nilai dari blok benang jika benang berjalan terjadi selama normal, pengecualian akan dibangkitkan lagi.
18 thr.wakeup
Negara ditangguhkan (stop) dari benang ke siap negara (run), jika metode ini dilakukan pada thread mati akan menaikkan pengecualian ThreadError.