Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Yukihiro Matsumoto_Programming Ruby.doc
Скачиваний:
121
Добавлен:
06.06.2015
Размер:
2.71 Mб
Скачать

Threads and Processes

Ruby gives you two basic ways to organize your program so that you can run different parts of it ``at the same time.'' You can split up cooperating tasks withinthe program, using multiple threads, or you can split up tasks between different programs, using multiple processes. Let's look at each in turn.

Multithreading

Often the simplest way to do two things at once is by using Ruby threads. These are totally in-process, implemented within the Ruby interpreter. That makes the Ruby threads completely portable---there is no reliance on the operating system---but you don't get certain benefits from having native threads. You may experience thread starvation (that's where a low-priority thread doesn't get a chance to run). If you manage to get your threads deadlocked, the whole process may grind to a halt. And if some thread happens to make a call to the operating system that takes a long time to complete, all threads will hang until the interpreter gets control back. However, don't let these potential problems put you off---Ruby threads are a lightweight and efficient way to achieve parallelism in your code.

Creating Ruby Threads

Creating a new thread is pretty straightforward. Here's a simple code fragment that downloads a set of Web pages in parallel. For each request it's given, the code creates a separate thread that handles the HTTP transaction.

require 'net/http'

pages = %w( www.rubycentral.com

            www.awl.com

            www.pragmaticprogrammer.com

           )

threads = []

for page in pages

  threads << Thread.new(page) { |myPage|

    h = Net::HTTP.new(myPage, 80)

    puts "Fetching: #{myPage}"

    resp, data = h.get('/', nil )

    puts "Got #{myPage}:  #{resp.message}"

  }

end

threads.each { |aThread|  aThread.join }

produces:

Fetching: www.rubycentral.com

Fetching: www.awl.com

Fetching: www.pragmaticprogrammer.com

Got www.rubycentral.com:  OK

Got www.pragmaticprogrammer.com:  OK

Got www.awl.com:  OK

Let's look at this code in more detail, as there are a few subtle things going on.

New threads are created with the Thread.new call. It is given a block that contains the code to be run in a new thread. In our case, the block uses thenet/httplibrary to fetch the top page from each of our nominated sites. Our tracing clearly shows that these fetches are going on in parallel.

When we create the thread, we pass the required HTML page in as a parameter. This parameter is passed on to the block as myPage. Why do we do this, rather than simply using the value of the variablepagewithin the block?

A thread shares all global, instance, and local variables that are in existence at the time the thread starts. As anyone with a kid brother can tell you, sharing isn't always a good thing. In this case, all three threads would share the variable page. The first thread gets started, andpageis set tohttp://www.rubycentral.com. In the meantime, the loop creating the threads is still running. The second time around,pagegets set tohttp://www.awl.com. If the first thread has not yet finished using thepagevariable, it will suddenly start using its new value. These bugs are difficult to track down.

However, local variables created within a thread's block are truly local to that thread---each thread will have its own copy of these variables. In our case, the variable myPagewill be set at the time the thread is created, and each thread will have its own copy of the page address.

Соседние файлы в папке Ruby