Почему мой файл не поврежден при записи в него из нескольких процессов в Python? - PullRequest
4 голосов
/ 05 июля 2019

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

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

Ничего не делая, файл кажется каким-то образом защищенным.

import multiprocessing
import random

NUM_WORKERS = 10
LINE_SIZE = 10000
NUM_LINES = 10000

def writer(i):
    line = ("%d " % i) * LINE_SIZE + "\n"
    with open("file.txt", "a") as file:
        for _ in range(NUM_LINES):
            file.write(line)

def check(file):
    for _ in range(NUM_LINES * NUM_WORKERS):
        values = next(file).strip().split()
        assert len(values) == LINE_SIZE
        assert len(set(values)) == 1

if __name__ == "__main__":
    processes = []

    for i in range(NUM_WORKERS):
        process = multiprocessing.Process(target=writer, args=(i, ))
        processes.append(process)

    for process in processes:
        process.start()

    for process in processes:
        process.join()

    with open("file.txt", "r") as file:
        check(file)

Я использую Linux, и я также знаю, что файл-запись может быть атомарной в зависимости от размера буфера: Является ли добавление файла атомарной в UNIX? .

Я пытался увеличить размер сообщений, но он не дает поврежденных данных.

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

1 Ответ

1 голос
/ 05 июля 2019

AFAIU, блокировка выполняется ядром. Причина, по которой вы видите эффекты блокировки, хотя вы и не просили об этом, заключается в том, что флаг состояния файла O_NONBLOCK по умолчанию не установлен (я полагаю, что при открытии файла).

Обратитесь к разделу руководства по флагам состояния файла , в частности, см. режимы работы и man 2 fcntl.

Я исправил ваш пример таким образом, чтобы увидеть эффекты O_NONBLOCK (и действительно, утверждение сейчас не работает):

--- 1.py.orig   2019-07-05 14:49:13.276289018 +0300
+++ 1.py        2019-07-05 14:51:11.674727731 +0300
@@ -1,5 +1,7 @@
 import multiprocessing
 import random
+import os
+import fcntl

 NUM_WORKERS = 10
 LINE_SIZE = 10000
@@ -8,6 +10,8 @@
 def writer(i):
     line = ("%d " % i) * LINE_SIZE + "\n"
     with open("file.txt", "a") as file:
+        flag = fcntl.fcntl(file.fileno(), fcntl.F_GETFD)
+        fcntl.fcntl(file.fileno(), fcntl.F_SETFL, flag | os.O_NONBLOCK)
         for _ in range(NUM_LINES):
             file.write(line)

Кредит: см., Например, это и это (и / или man 3p write).

...