2013-05-20 36 views
8

Tôi không hiểu làm thế nào dưới đây:Điểm của sợi trong Ruby là gì?

counts = Hash.new(0) 

File.foreach("testfile") do |line| 
    line.scan(/\w+/) do |word| 
    word = word.downcase 
    counts[word] += 1 
    end 
end 

counts.keys.sort.each {|k| print "#{k}:#{counts[k]} "} 

là nên tồi tệ hơn nhiều so với:

words = Fiber.new do 
    File.foreach("testfile") do |line| 
    line.scan(/\w+/) do |word| 
     Fiber.yield word.downcase 
    end 
    end 
end 

counts = Hash.new(0) 

while word = words.resume 
    counts[word] += 1 
end 

counts.keys.sort.each {|k| print "#{k}:#{counts[k]} "} 

Trả lời

24

Sợi là một cách để tạm dừng và khôi phục khối tùy ý mã. Một ví dụ như thế này không thực sự là một trường hợp sử dụng tuyệt vời vì nó không cung cấp bất kỳ lợi thế thực nào so với cách đọc truyền thống trong các dòng và xử lý chúng.

Trong ví dụ cụ thể này, nếu bạn muốn làm cho nó tốt hơn, bạn muốn viết một giao diện điều tra viên theo phong cách, do đó bạn có thể viết:

words = WordsReader.new("testfile") 

words.each do |word| 
    # ... 
end 

đâu Sợi trở nên quan trọng là bằng văn bản mã không đồng bộ. Ví dụ: bên trong môi trường EventMachine bạn cần có thể thực hiện cuộc gọi không đồng bộ, tạm dừng một khối mã và tiếp tục lại khi bạn nhận được phản hồi.

này kết thúc lên tim như thế này:

async_call(argument1, argument2) do |response_1| 
    if (response_1.ok?) 
    async_call(argument3, argument4) do |response_2| 
     if (response_2.ok?) 
     async_call(argument5, argument6) do |response_3| 
      if (response_3.ok?) 
      do_something(response_1, response_2, response_3) 
      else 
      panic_and_fail! 
      end 
     end 
     else 
     panic_and_fail! 
     end 
    end 
    else 
    panic_and_fail! 
    end 
end 

Điều này loại lồng nhau, cấu trúc gọi lồng nhau và tái lồng nhau được lỏng lẻo gọi là "gọi lại địa ngục" vì nó rất khó để quản lý một lần logic của bạn trở nên phi không đáng kể. Một cách để làm phẳng cấu trúc này là sử dụng sợi. Một tương đương đúng Fiber-ized là:

begin 
    response_1 = fiber_call(argument1, argument2) 
    response_2 = fiber_call(argument3, argument4) 
    response_3 = fiber_call(argument5, argument6) 

    do_something(response_1, response_2, response_3) 

rescue NotOkay 
    panic_and_fail! 
end 

Sợi có thể tận dụng các ngoại lệ, nơi callback-loại mã không thể. Các ngoại lệ, khi được sử dụng hiệu quả, có thể đơn giản hóa một khối mã, như bạn có thể thấy ở đây. Thay vì thử nghiệm cho ok? trên mỗi phản hồi, dự kiến ​​rằng cuộc gọi sẽ ném một ngoại lệ loại NotOkay thay thế.

Gọi lại không thể ném đáng tin cậy ngoại lệ vì người khởi xướng cuộc gọi đã rơi ra khỏi phạm vi khi cuộc gọi lại xảy ra. Đây là một hạn chế cơ bản của lập trình không đồng bộ với các cuộc gọi lại. Mã điều khiển sợi duy trì một ngăn xếp cuộc gọi thích hợp, nó chỉ đơn thuần là bị treo và tiếp tục như hiện trạng, vì vậy các trường hợp ngoại lệ được xếp chồng đúng cách thông qua người gọi.

Tôi đã tìm thấy Sợi đơn giản dễ hiểu và rất khó áp dụng chính xác. Hầu hết thời gian bạn sẽ không phải sử dụng chúng trực tiếp, bạn sẽ sử dụng thư viện sử dụng chúng thay thế. Việc viết mã "Nhận biết sợi" không giống như viết mã "Thread-safe". Nó có thể được khôn lanh để có được quyền.

+4

Bạn đã viết tất cả điều đó sau 17 phút? –

+3

Dường như vậy. Không biết tôi đã bị hẹn giờ! – tadman

+2

Wow Tadman, tôi thực sự đánh giá cao chiều sâu bạn đã đi đến để giải thích điều này với tôi và bất cứ ai có thể gặp phải nó. Tôi rất trân trọng điều này. Xin chào từ một người Canada khác! :) – Senjai