Вход/Регистрация
Программирование на языке Ruby
вернуться

Фултон Хэл

Шрифт:

sleep 10

headwaiter = Thread.new { waitfor("head") }

# Основной поток занимается другими делами...

Есть много ситуаций, когда поток должен ожидать внешнего события (например, в сетевых приложениях так бывает, когда сервер на другом конце соединения работает медленно или ненадежно).

13.2.8. Продолжение обработки во время ввода/вывода

Часто приложению приходится выполнять одну или более длительных операций ввода/вывода. Прежде всего, речь идет о вводе данных с клавиатуры, поскольку человек печатает куда медленнее, чем вращается диск. Это время можно употребить на пользу с помощью потоков.

Возьмем, к примеру, шахматную программу, которая должна ждать, пока человек сделает ход. Конечно, мы можем изложить только сам принцип, не вдаваясь в технические детали.

Предположим, что итератор

predict_move
генерирует вероятные ходы человека (и ответные ходы программы). Тогда в момент, когда человек сделает ход, не исключено, что у компьютера уже будет готов ответ.

scenario = {} # Хэш ход-ответ.

humans_turn = true

thinking_ahead = Thread.new(board) do

 predict_move do |m|

scenario[m] = my_response(board,m)

Thread.exit if humans_turn == false

 end

end

human_move = get_human_move(board)

humans_turn = false # Остановить поток.

# Теперь можно посмотреть, нет ли в хэше scenario хода,

# сделанного пользователем...

Конечно, настоящие шахматные программы работают не так.

13.2.9. Реализация параллельных итераторов

Предположим, что нужно параллельно обходить несколько объектов, то есть для каждого объекта найти первый элемент, потом второй, потом третий и т.д.

Рассмотрим следующий пример. Пусть

compose
— имя магического метода, который выполняет композицию итераторов. Допустим еще, что у каждого объекта есть стандартный итератор
each
и что каждый объект возвращает по одному элементу на каждой итерации.

arr1 = [1, 2, 3, 4]

arr2 = [5, 10, 15, 20]

compose(arr1, arr2) {|a,b| puts "#{а} и #{b}" }

# Должно быть напечатано:

# 1 и 5

# 2 и 10

# 3 и 15

# 4 и 20

Можно было бы, конечно, использовать для этой цели

zip
. Но если нужно более элегантное решение, при котором все элементы не будут храниться одновременно, то без потоков не обойтись. Такое решение представлено в листинге 13.7.

Листинг 13.7. Параллельные итераторы

def compose(*objects)

 threads = []

 for obj in objects do

threads << Thread.new(obj) do |myobj|

me = Thread.current

me[:queue] = []

myobj.each {|x| me[:queue].push(x) }

end

 end

 list = [0] # Фиктивное значение, отличное от nil.

 while list.nitems > 0 do # Еще есть не nil.

list = []

for thr in threads

list << thr[:queue].shift # Удалить по одному из каждого.

end

yield list if list.nitems > 0 # He вызывать yield, если все равны nil.

 end

end

x = [1, 2, 3, 4, 5, 6, 7, 8]

y = " первый\n второй\n третий\n четвертый\n пятый\n"

z = %w[a b с d e f]

compose(x, у, z) {|a,b,c| p [a, b, c] }

# Выводится:

# [1, " первый\n", "a"]

# [2, " второй\n", "b"]

# [3, " третий\n", "c"]

# [4, " четвертый\n", "d"]

# [5, " пятый\n", "e"]

# [6, nil, "f"]

# [7, nil, nil]

# [8, nil, nil]

  • Читать дальше
  • 1
  • ...
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: