2017-01-17 5 views
1

У меня есть база данных, заполненная строками и несколькими потоками, которые обращаются к этим строкам, вводят некоторые данные из них в функцию, производя вывод, а затем заполняя отсутствующие столбцы строки с выходом.Как «блокировать» обрабатываемые строки базы данных

В этой строке: Каждая строка имеет флаг unprocessed, который по умолчанию является истинным. Поэтому каждый поток ищет строки с этим флагом. Но каждый поток получает САМУЮ строку, получается ... потому что строка помечена как обработанная после завершения работы потока, что может произойти через несколько секунд.

Один из способов избежать этого - вставить флаг currently_processed для каждой строки, пометить его как false, и как только поток обратится к строке, измените ее на true. Затем, когда поток будет выполнен, просто измените, если он вернулся к false. Проблема в том, что я должен использовать какую-то блокировку и не позволять никому другому потоку ничего делать, пока это не произойдет. Мне было интересно, есть ли альтернативный подход, когда мне не нужно будет блокировать потоки (через мьютекс или что-то еще) и тем самым замедлить весь процесс.

Если это помогает, код находится в Ruby, но эта проблема является агностикой языка, но вот код, демонстрирующий тип потоков, которые я использую. Так что ничего особенного, резьб на самом низком уровне, как почти во всех языках есть:

3.times do 
    Thread.new do 
    row = get_database_row 
    result = do_some_processing(row) 
    insert_results_into_row(result) 
    end 
end.each(&:join) 

ответ

2

«Реального» ответ здесь является то, что вам нужно транзакциюбазы данных. Когда один поток получает эту строку, то база должна знать, что эта строка в настоящее время готова для обработки.

Вы не можете решить это в своем приложении! Видите ли, когда два потока смотрят на одну и ту же строку одновременно, они могут и попытаться записать этот флаг ... и, конечно, он изменится на «обработанный»; а затем оба потока будут обновлять данные строк и записывать их обратно. Может быть, это не проблема, если какая-либо обработка результатов в равна конечный результат; но если нет, тогда возникнут все проблемы целостности данных.

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

+0

В то время, как в процессе трансляции другие потоки должны ждать, верно? Я не вижу, как это отличается от мьютекса. Ofc, это на уровне базы данных, но есть ли какая-либо функциональная разница? – anemaria20

+1

Ваш * mutex * - это то, что живет в вашем приложении. Как написано: вы не можете предположить, что чтение двух чтений, чем запись этого поля ** в **, приведет к правильным результатам. Да, вам не нужно использовать базу данных, но дело в том, что это одна из точек использования базы данных - с этим уровнем контроля. Понимаете, вы просто предлагаете ** пересоздать ** колесо здесь, в вашем приложении. У вас есть шансы: вы получите это неправильно. – GhostCat

+1

@ anemaria20: реальный мьютекс будет работать, но ваше исходное описание флага 'current_processed' не будет работать. Флаг 'current_processed' может выглядеть как мьютекс, но мьютекс обладает дополнительным свойством: есть гарантии низкого уровня, что ни один из двух потоков не может одновременно устанавливать mutex. Аналогичным образом транзакции представляют собой функцию БД, которая предоставляет такие гарантии. Таким образом, транзакции в основном состоят в том, как базы данных предоставляют возможности, подобные mutex. – slebetman

0

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

Есть несколько способов сделать это:

1) Один общий диспетчеру для всех потоков. Он должен читать все строки и помещать их в общую очередь, откуда обрабатываются теги, получая строки.

2) Пойдите глубже в БД, узнайте, поддерживает ли он что-то вроде синтаксиса «выбрать для обновления пропустить блокировку» и использовать его. Для оракула вам нужно использовать его синтаксис в курсоре и сделать несколько громоздкое взаимодействие, но по крайней мере он может работать таким образом.

3) Вход в раздел, скажем, индекс рабочей нити. Итак, 1-й рабочий из 3 будет обрабатывать только строки 1,4,7 и т. Д. 2-й рабочий будет обрабатывать только строки 2, 5, 8 и т. Д.