Безопасно ли направлять вывод нескольких параллельных процессов в один файл, используя >>? - PullRequest
37 голосов
/ 15 марта 2010

Я собираю данные из Интернета, и у меня несколько процессов моего скребка работают параллельно.

Я хочу, чтобы вывод каждого из этих процессов заканчивался в одном файле. Пока строки текста остаются нетронутыми и не смешиваются друг с другом, порядок строк не имеет значения. В UNIX я могу просто направить вывод каждого процесса в один и тот же файл, используя оператор >>?

Ответы [ 9 ]

28 голосов
/ 15 марта 2010

Нет. Не гарантируется, что линии останутся нетронутыми. Они могут смешаться.

По результатам поиска, основанного на ответе Лиори, я нашел this :

Запросы на запись байтов {PIPE_BUF} или меньше не должны чередоваться с данными из других процессов, выполняющих запись в том же канале. При записи более байтов {PIPE_BUF} данные могут чередоваться на произвольных границах с записями других процессов независимо от того, установлен флаг O_NONBLOCK флагов состояния файла.

Таким образом, строки, длина которых превышает {PIPE_BUF} байт, не гарантированно остаются неизменными.

12 голосов
/ 09 сентября 2011

Одна, возможно, интересная вещь, которую вы могли бы сделать, это использовать gnu параллельно: http://www.gnu.org/s/parallel/ Например, если вы делали паузы на сайтах:

stackoverflow.com, stackexchange.com, fogcreek.com 

Вы могли бы сделать что-то вроде этого

(echo stackoverflow.com; echo stackexchange.com; echo fogcreek.com) | parallel -k your_spider_script

и выходные данные буферизуются параллельно и из-за опции -k, возвращенной вам в порядке списка сайтов выше. Реальный пример (в основном скопированный из 2-го параллельного экрана):

 ~ $ (echo stackoverflow.com; echo stackexchange.com; echo fogcreek.com) | parallel -k ping -c 1 {}


PING stackoverflow.com (64.34.119.12): 56 data bytes

--- stackoverflow.com ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss
PING stackexchange.com (64.34.119.12): 56 data bytes

--- stackexchange.com ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss
PING fogcreek.com (64.34.80.170): 56 data bytes
64 bytes from 64.34.80.170: icmp_seq=0 ttl=250 time=23.961 ms

--- fogcreek.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 23.961/23.961/23.961/0.000 ms

В любом случае, мммм

7 голосов
/ 15 марта 2010

Как правило, нет.

В Linux это возможно, если выполняются два условия: каждая строка записывается в одной операции, а строка не длиннее PIPE_SIZE (обычно совпадаетPAGE_SIZE, обычно 4096).Но ... я бы на это не рассчитывал;это поведение может измениться.

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

3 голосов
/ 15 марта 2010

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

Если я пытаюсь получить данные из нескольких источников, гораздо проще (и легче отлаживать) иметь несколько файлов «бумажных трасс», а если мне нужен общий файл журнала, объединить на основе метки времени (вы Вы используете метки времени, верно?) или, как сказал Лиори, системный журнал.

3 голосов
/ 15 марта 2010

Используйте временные файлы и объединяйте их вместе.Это единственный безопасный способ сделать то, что вы хотите, и таким образом (вероятно) будет незначительная потеря производительности.Если производительность действительно является проблемой, попробуйте убедиться, что ваш каталог / tmp является файловой системой на основе ОЗУ и поместите туда свои временные файлы.Таким образом, временные файлы хранятся в оперативной памяти, а не на жестком диске, поэтому чтение / запись их происходит практически мгновенно.

3 голосов
/ 15 марта 2010

Вам необходимо убедиться, что вы пишете целые строки в одной операции записи (поэтому, если вы используете какую-либо форму stdio, вам нужно будет установить ее для буферизации строки по крайней мере на длину самого длинного строка, которую вы можете вывести.) Поскольку оболочка использует O_APPEND для перенаправления >>, тогда все ваши записи будут автоматически добавлены в файл без дальнейших действий с вашей стороны.

1 голос
/ 15 марта 2010

Вкратце, нет. >> не поддерживает несколько процессов.

0 голосов
/ 12 января 2013

Как уже упоминалось выше, это довольно взломанный, но работает довольно хорошо =)

( ping stackoverflow.com & ping stackexchange.com & ping fogcreek.com ) | cat

то же самое с '>>':

( ping stackoverflow.com & ping stackexchange.com & ping fogcreek.com ) >> log

и с последним exec вы сохраните один процесс:

( ping stackoverflow.com & ping stackexchange.com & exec ping fogcreek.com ) | cat
0 голосов
/ 15 марта 2010

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

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

...