Версия asyn c работает медленнее, чем версия без asyn c - PullRequest
1 голос
/ 02 февраля 2020

Моя программа выполняет следующие действия:

  1. Принимает папку .txt файлов
  2. Для каждого файла:

    2.1. читать файл

    2.2 сортировать содержимое в виде списка и помещать список в основной список

Я сделал это без какой-либо асинхронности / ожидания, и это статистика времени

real    0m0.036s

user    0m0.018s

sys     0m0.009s

С приведенным ниже кодом асинхронного ожидания / ожидания я получаю

real    0m0.144s

user    0m0.116s

sys     0m0.029s

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

У кого-нибудь есть идея что я делаю не так?

import asyncio
import aiofiles
import os

directory = "/tmp"
listOfLists = list()

async def sortingFiles(numbersInList):
    numbersInList.sort()

async def awaitProcessFiles(filename,numbersInList):
    await readFromFile(filename,numbersInList)
    await sortingFiles(numbersInList)
    await appendToList(numbersInList)


async def readFromFile(filename,numbersInList):
    async with aiofiles.open(directory+"/"+filename, 'r') as fin:
        async for line in fin:
            return numbersInList.append(int(line.strip("\n"),10))            
    fin.close()    

async def appendToList(numbersInList):
    listOfLists.append(numbersInList)

async def main():
    tasks=[]
    for filename in os.listdir(directory):
        if filename.endswith(".txt"):  
            numbersInList =list()
            task=asyncio.ensure_future(awaitProcessFiles(filename,numbersInList))
            tasks.append(task)
    await asyncio.gather(*tasks)   

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

Информация о профилировании:

        151822 function calls (151048 primitive calls) in 0.239 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       11    0.050    0.005    0.050    0.005 {built-in method _imp.create_dynamic}
       57    0.022    0.000    0.022    0.000 {method 'read' of '_io.BufferedReader' objects}
       57    0.018    0.000    0.018    0.000 {built-in method io.open_code}
      267    0.012    0.000    0.012    0.000 {method 'control' of 'select.kqueue' objects}
       57    0.009    0.000    0.009    0.000 {built-in method marshal.loads}
      273    0.009    0.000    0.009    0.000 {method 'recv' of '_socket.socket' objects}
      265    0.005    0.000    0.098    0.000 base_events.py:1780(_run_once)
      313    0.004    0.000    0.004    0.000 {built-in method posix.stat}
      122    0.004    0.000    0.004    0.000 {method 'acquire' of '_thread.lock' objects}
  203/202    0.003    0.000    0.011    0.000 {built-in method builtins.__build_class__}
     1030    0.003    0.000    0.015    0.000 thread.py:158(submit)
     1030    0.003    0.000    0.009    0.000 futures.py:338(_chain_future)
     7473    0.003    0.000    0.003    0.000 {built-in method builtins.hasattr}
     1030    0.002    0.000    0.017    0.000 futures.py:318(_copy_future_state)
       36    0.002    0.000    0.002    0.000 {built-in method posix.getcwd}
     3218    0.002    0.000    0.077    0.000 {method 'run' of 'Context' objects}
     6196    0.002    0.000    0.003    0.000 threading.py:246(__enter__)
     3218    0.002    0.000    0.078    0.000 events.py:79(_run)
     6192    0.002    0.000    0.004    0.000 base_futures.py:13(isfuture)
     1047    0.002    0.000    0.002    0.000 threading.py:222(__init__)

Создайте несколько тестовых файлов ...

import random, os
path = <directory name here>
nlines = range(1000)
nfiles = range(1,101)
for n in nfiles:
    fname = f'{n}.txt'
    with open(os.path.join(path,fname),'w') as f:
        for _ in nlines:
            q = f.write(f'{random.randrange(1,10000)}\n')

1 Ответ

4 голосов
/ 03 февраля 2020

asyncio не имеет большого смысла для локальных файлов. По этой причине даже в стандартной библиотеке python их нет.

async for line in fin:

Обратите внимание на приведенную выше строку. Событие l oop приостанавливает подпрограмму для каждой прочитанной строки и выполняет другую подпрограмму. Это означает, что следующие строки файла в кэше процессора просто выбрасываются, чтобы освободить место для следующей подпрограммы. (Тем не менее, они все еще будут в ОЗУ.)

Когда следует использовать файлы aiofile?

Предположим, что вы уже используете асиновый код c в своей программе, и иногда у вас есть сделать некоторую обработку файла. Если обработка файла была выполнена в том же событии l oop, все другие подпрограммы будут заблокированы. В этом случае вы можете использовать aiofiles или выполнить обработку в другом исполнителе.

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

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