Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
humans_turn = false # Остановить поток.# Теперь можно посмотреть, нет ли в хэше scenario хода,# сделанного пользователем...Конечно, настоящие шахматные программы работают не так.
13.2.9. Реализация параллельных итераторов
Предположим, что нужно параллельно обходить несколько объектов, то есть для каждого объекта найти первый элемент, потом второй, потом третий и т.д.
Рассмотрим следующий пример. Пусть
composeeacharr1 = [1, 2, 3, 4]arr2 = [5, 10, 15, 20]compose(arr1, arr2) {|a,b| puts "#{а} и #{b}" }# Должно быть напечатано:# 1 и 5# 2 и 10# 3 и 15# 4 и 20Можно было бы, конечно, использовать для этой цели
zipdef 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. endendx = [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Конечно, можно написать и более общий метод, который на каждой итерации будет обрабатывать более одного элемента. (В конце концов, не все итераторы возвращают по одному значению за раз.) Можно было бы в первом параметре передавать число значений для каждого итератора.
Можно также пользоваться произвольными итераторами (а не только стандартным
eachsendВпрочем, мы полагаем, что приведенного кода достаточно для большинства целей. Вариации на эту тему оставляем читателю в качестве упражнения.
13.2.10. Параллельное рекурсивное удаление
Забавы ради напишем код, который будет удалять дерево каталогов. Процедура рекурсивного удаления использует потоки. Как только обнаруживается очередной подкаталог, мы запускаем новый поток, который будет обходить его и удалять содержимое.
Созданные в ходе работы программы потоки хранятся в массиве
threadsОтметим также, что в блок потока передается полное имя файла
fullnamefnПрежде чем удалять очередной каталог, мы должны дождаться завершения всех созданных в процессе его обхода потоков.
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) } else File.delete(fullname) end end threads.each { |t| t.join } Dir.delete(dir)enddelete_all("/tmp/stuff")Будет ли работать такая программа быстрее, чем ее вариант без потоков? В наших тестах получалось по-разному. Возможно, это зависит от операционной системы и структуры конкретного каталога — глубины, количества файлов и т.д.
