Как добиться более быстрого файлового ввода-вывода в Python? - PullRequest
0 голосов
/ 13 октября 2018

У меня скорость / эффективность связанный вопрос о Python :

Мне нужно извлечь несколько полей из вложенного файла JSON (после записи в .txt файлы, они имеют ~ 64k строк, и текущий фрагмент делает это за ~ 9 минут ), где каждая строка может содержать плавающие и строковые значения.

Обычно япросто поместил бы все мои данные в numpy и использовал бы np.savetxt() для его сохранения ..

Я прибег к простой сборке строк в виде строк, но это немного медленный .Пока что я делаю:

  • Собрать каждую строку в виде строки (извлечь нужное поле из JSON)
  • Записать строку в соответствующий файл

У меня есть несколько проблем с этим: - это приводит к более отдельным file.write() командам, которые тоже очень медленные .. (около 64k * 8 вызовов (для 8 файлов))

Итак, мой вопрос:

  • Какова хорошая рутина для такого рода проблем?Тот, который уравновешивает speed vs memory-consumption для наиболее эффективной записи на диск.
  • Должен ли я увеличить DEFAULT_BUFFER_SIZE?(сейчас 8192)

Я проверил Файловый ввод / вывод на каждом языке программирования и python org: IO , но это не сильно помоглокроме (в моем понимании после прохождения через него файл io уже должен быть буферизован в python 3.6.x), и я обнаружил, что по умолчанию DEFAULT_BUFFER_SIZE составляет 8192.

Заранее спасибо за помощь !!

Вот часть моего фрагмента -

def read_json_line(line=None):
    result = None
    try:        
        result = json.loads(line)
    except Exception as e:      
        # Find the offending character index:
        idx_to_replace = int(str(e).split(' ')[-1].replace(')',''))      
        # Remove the offending character:
        new_line = list(line)
        new_line[idx_to_replace] = ' '
        new_line = ''.join(new_line)     
        return read_json_line(line=new_line)
    return result

def extract_features_and_write(path_to_data, inp_filename, is_train=True):
    # It's currently having 8 lines of file.write(), which is probably making it slow as writing to disk is  involving a lot of overheads as well
    features = ['meta_tags__twitter-data1', 'url', 'meta_tags__article-author', 'domain', 'title', 'published__$date',\
                'content', 'meta_tags__twitter-description']

    prefix = 'train' if is_train else 'test'

    feature_files = [open(os.path.join(path_to_data,'{}_{}.txt'.format(prefix, feat)),'w', encoding='utf-8')
                    for feat in features]

    with open(os.path.join(PATH_TO_RAW_DATA, inp_filename), 
              encoding='utf-8') as inp_json_file:
​
        for line in tqdm_notebook(inp_json_file):
            for idx, features in enumerate(features):
                json_data = read_json_line(line)  
​
                content = json_data['meta_tags']["twitter:data1"].replace('\n', ' ').replace('\r', ' ').split()[0]
                feature_files[0].write(content + '\n')
​
                content = json_data['url'].split('/')[-1].lower()
                feature_files[1].write(content + '\n')
​
                content = json_data['meta_tags']['article:author'].split('/')[-1].replace('@','').lower()
                feature_files[2].write(content + '\n')
​
                content = json_data['domain']
                feature_files[3].write(content + '\n')
​
                content = json_data['title'].replace('\n', ' ').replace('\r', ' ').lower()
                feature_files[4].write(content + '\n')
​
                content = json_data['published']['$date']
                feature_files[5].write(content + '\n')
​
                content = json_data['content'].replace('\n', ' ').replace('\r', ' ')
                content = strip_tags(content).lower()
                content = re.sub(r"[^a-zA-Z0-9]", " ", content)
                feature_files[6].write(content + '\n')
​
                content = json_data['meta_tags']["twitter:description"].replace('\n', ' ').replace('\r', ' ').lower()
                feature_files[7].write(content + '\n')

1 Ответ

0 голосов
/ 13 октября 2018

Из комментария:

почему вы думаете, что 8 записей приводят к 8 физическим операциям записи на ваш жесткий диск?Файловый объект сам по себе буферизует, что записывать, если он решит записать в вашу ОС, ваша ОС может также немного подождать, пока он не выполнит физическую запись - и даже тогда ваши хардрайверы получат буферы, которые могут сохранять содержимое файлов некоторое время, пока не запустится.чтобы действительно написать.См. Как часто Python выполняет сброс в файл?


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

Лучшее, что можно сделать, это очистить ваши данные перед подачей их вjson.load () ... следующее, что лучше всего сделать, это избежать повторения ... попробуйте что-то вроде:

def read_json_line(line=None):
    result = None

    while result is None and line: # empty line is falsy, avoid endless loop
        try:        
            result = json.loads(line)
        except Exception as e:
            result = None      
            # Find the offending character index:
            idx_to_replace = int(str(e).split(' ')[-1].replace(')',''))      
            # slice away the offending character:
            line = line[:idx_to_replace]+line[idx_to_replace+1:]

     return result
...