Для того, чтобы продемонстрировать отличия можно воспользоваться следующих кодом. Идея работы скрипта достаточно проста: запускается 10 потоков, каждый из которых выводит в стандартный вывод по 10 раз строку "line" с номером от 0 до 9.
import sys
import threading
class PrintThread(threading.Thread):
def run(self):
for i in range(10):
print 'line %d' % i
if __name__ == '__main__':
for i in range(10):
PrintThread().start()Для данного кода вывод будет следующим (символ перевода строки умышлено убран для лучшего восприятия):line 0 line 1line 0 line 2line 1 line 3line 2line 0 line 4line 3line 1 line 4line 0line 5line 2 line 5line 6line 0line 1line 3Видно, что данные выводятся на экран в неупорядоченном виде. Если изменить скрипт и вместо функции print использовать sys.stdout.write
import sys
import threading
class SysWriteThread(threading.Thread):
def run(self):
for i in range(10):
sys.stdout.write('line %d\n' % i)
if __name__ == '__main__':
for i in range(10):
SysWriteThread().start()Логика скрипта изменена незначительно, а вот вывод изменился достаточно сильноline 0 line 1 line 2 line 0 line 3 line 1 line 4 line 2 line 0 line 5 line 3 line 1 line 6 line 4 line 2 line 7 line 0 line 5Из этих примеров можно сделать вывод, что использование sys.stdout предпочтительней, чем print для многопотоковых приложений. Это позволяет получить лог-файлы более структурировано. К сожалению узнать природу данного явления и объяснить подобное поведение более подробно затруднительно, так как print является встроенной функцией, а sys является встроенным модулем. Если кто-то может объяснить почему это работает именно так, всегда рад услышать развернутый ответ.



Заблуждаешься, что stdout будет правильно работать при многострунности. Просто твой код пишет очень мало и квантов достаточно чтобы записать строку в stdout буфер. Любой логгер должен идти через mutex. Точка. Кстати, небуферизируемый stderr не поможет - все равно можно влезть в середину буфера.
ОтветитьУдалитьА в первом случае, если ты имеешь в виду, что каждый вывод не в новой строке как в stdout, то, может, здесь есть "привкус" perl-а?
Спасибо за идею с mutex. С деталями буду разбираться. Интересно какой должен быть поток, чтобы забить буфер?
ОтветитьУдалитьпроверил на тысяче одновременных потоках, каждый из которых выводит в stdout тысячу 80 байтовых строк. Пересечения не было.
ОтветитьУдалитьпри проверке функциональности процессами (4 процесса, 1000 выводов 80-ти байтовой строки на каждый процесс), пересечения появляются для stdout. Так что решение с stdout при увеличении нагрузки себя не оправдывает. Нужно использовать другие методы
ОтветитьУдалить