Чтение онлайн

на главную - закладки

Жанры

Программирование на языке Ruby
Шрифт:

 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]

Обратите внимание: мы не предполагаем, что все объекты имеют одно и то же число элементов. Если один итератор доходит до конца раньше остальных, то он будет генерировать значения

nil
до тех пор, пока не закончит работу «самый длинный» итератор.

Конечно, можно написать и более общий метод, который на каждой итерации будет обрабатывать более одного элемента. (В конце концов, не все итераторы возвращают по одному значению за раз.) Можно было бы в первом параметре передавать число значений для каждого итератора.

Можно также пользоваться произвольными итераторами (а не только стандартным

each
). Их имена можно было бы передавать в виде строк, а вызывать с помощью метода
send
. Много чего еще можно придумать.

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

13.2.10. Параллельное рекурсивное удаление

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

Созданные в ходе работы программы потоки хранятся в массиве

threads
. Поскольку это локальная переменная, у каждого потока будет собственная копия массива. Раз к ней может обращаться всего один поток, синхронизировать доступ не надо.

Отметим также, что в блок потока передается полное имя файла

fullname
, чтобы не нужно было беспокоиться по поводу того, что поток обращается к переменной, которую кто-то еще изменяет. Поток делает для себя локальную копию
fn
этой переменной.

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

def delete_all(dir)

 threads = []

 Dir.foreach(dir) do |e|

next if [".",".."].include? e # Пропустить . и ..

fullname = dir + "/" + e

if FileTest.directory?(fullname)

threads << Thread.new(fullname) {|fn| delete_all(fn) }

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

Газлайтер. Том 21

Володин Григорий Григорьевич
21. История Телепата
Фантастика:
боевая фантастика
аниме
попаданцы
5.00
рейтинг книги
Газлайтер. Том 21

Охотник на демонов

Шелег Дмитрий Витальевич
2. Живой лёд
Фантастика:
боевая фантастика
5.83
рейтинг книги
Охотник на демонов

Я уже барон

Дрейк Сириус
2. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я уже барон

Локки 6. Потомок бога

Решетов Евгений Валерьевич
6. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Локки 6. Потомок бога

Девочка из прошлого

Тоцка Тала
3. Айдаровы
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Девочка из прошлого

Отмороженный 7.0

Гарцевич Евгений Александрович
7. Отмороженный
Фантастика:
рпг
аниме
5.00
рейтинг книги
Отмороженный 7.0

Хозяин Теней 3

Петров Максим Николаевич
3. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Хозяин Теней 3

Лекарь Империи 6

Карелин Сергей Витальевич
6. Лекарь Империи
Фантастика:
городское фэнтези
боевая фантастика
аниме
попаданцы
5.00
рейтинг книги
Лекарь Империи 6

Рассвет русского царства 3

Грехов Тимофей
3. Новая Русь
Фантастика:
историческое фэнтези
альтернативная история
5.00
рейтинг книги
Рассвет русского царства 3

Стеллар. Трибут

Прокофьев Роман Юрьевич
2. Стеллар
Фантастика:
боевая фантастика
рпг
8.75
рейтинг книги
Стеллар. Трибут

Двойник Короля 6

Скабер Артемий
6. Двойник Короля
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Двойник Короля 6

Истребители. Трилогия

Поселягин Владимир Геннадьевич
Фантастика:
альтернативная история
7.30
рейтинг книги
Истребители. Трилогия

Курсант: назад в СССР 2

Дамиров Рафаэль
2. Курсант
Фантастика:
попаданцы
альтернативная история
6.33
рейтинг книги
Курсант: назад в СССР 2

Князь Андер Арес 2

Грехов Тимофей
2. Андер Арес
Фантастика:
рпг
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Князь Андер Арес 2