Одновременная запись в несколько файлов с помощью asyncio

#python #python-asyncio

Вопрос:

Каков шаблон проектирования для записи в несколько файлов с использованием asyncio ?

Вот краткое изложение однопоточной версии того, что я хочу сделать.

 
import datetime
import json

def generate_records():
   for i in range(100):
       # simulate some JSON content that I want to write to a file
       # assume that this takes some significant amount of time
       yield {
         'index':index,
         'message':f"Message {index}",
         'timestamp':datetime.datetime.now().isoformat()
       }



for (i,r) in enumerate(generate_records()):
    with open(f"record_{i:04}.json", 'w') as fout:
         json.dump(r, fout)

 

Как можно использовать asyncio для записи этих файлов одновременно с созданием записей?

Комментарии:

1. asyncio следует использовать с циклом событий, чтобы один поток мог асинхронно принимать запросы на запись в разные файлы (что считается медленным вводом-выводом). Видишь codeflex.co/python3-async-await-example/?amp

2. Асинхронная запись на один и тот же диск не повышает общую производительность.

3. @yoonghm цель состоит в том, чтобы иметь возможность записывать на диск одновременно с повторением данных. Я постарался сделать пример простым, чтобы он был сосредоточен на части asyncio. Обновлено, чтобы лучше отразить то, к чему я клоню.

4. @yoonghm: На самом деле это может быть, по крайней мере, для вращающихся дисков; если в ОС несколько записей в очереди, она может изменить их порядок, чтобы они записывались по порядку, поскольку головка диска выполняет один проход изнутри наружу диска (или наоборот). Представьте, что на диске были дорожки ABCDEFGH изнутри наружу; если головка диска находится в точке A, а вы одновременно записываете в B, D и F, он может выполнять запись за одно сканирование. Последовательные записи в F, затем в, затем D приводят к увеличению задержки поиска. По общему признанию, за исключением sync вызовов, ОС обычно кэширует записи и в любом случае переупорядочивает их, но возможно улучшение производительности.

5. @ShadowRanger, технология дисководов настигла меня. Спасибо

Ответ №1:

 import json
import datetime
import aiofiles

async def main():
    def mk_record(index):
        # simulate some JSON content that I want to write to a file
        return {
            'index': index,
            'message': f"Message {index}",
            'timestamp': datetime.datetime.now().isoformat()
        }
    records = [mk_record(i) for i in range(100)]

    async def write_record(i, r):
        # Test by pretending the write takes a while
        # Delete this line for actual code.
        await asyncio.sleep(1)
        async with aiofiles.open(f'/tmp/record_{i:04}.json', mode='w') as fout:
            await fout.write(json.dumps(r))

    await asyncio.gather(*[write_record(i, r) for i, r in enumerate(records)])


if __name__ == '__main__':
    asyncio.run(main())
 

Комментарии:

1. Ух. Извините. В моем первоначальном ответе была ошибка, и мне пришлось ее исправить. Запись записей все еще происходила одна за другой. Я понял, что должен изменить его так, чтобы написание каждой записи было отдельной задачей. Исправлено выше.