2015-12-24 3 views
7

У меня есть несколько файлов gz с общим размером около 120 ГБ. Я хочу разархивировать (gzip) эти файлы в тот же каталог и удалить существующий gz-файл. В настоящее время мы делаем это вручную, и у вас больше времени на распаковку, используя gzip -d <filename>.
Есть ли способ, которым я могу разархивировать эти файлы параллельно, создав скрипт python или любую другую технику. В настоящее время эти файлы находятся на машине Linux.Как распаковать несколько файлов gz в python, используя многопоточность?

ответ

0

Большая часть времени настенных часов, потраченная на распаковку файла с gunzip или gzip -d, будет осуществляться из операций ввода-вывода (чтение и запись на диск). Это может быть даже больше, чем время, затрачиваемое на декомпрессию данных. Вы можете воспользоваться этим, имея несколько заданий gzip, идущих в фоновом режиме. Поскольку некоторые операции блокируются при вводе-выводе, другое задание может выполняться без ожидания в очереди.

Вы можете ускорить процесс распаковки всего набора файлов, выполнив несколько фоновых процессов gunzip. Каждый из них обслуживает определенный набор файлов.

Вы можете взломать что-то легкое в BASH. Разделите список файлов на отдельные команды и используйте &, чтобы запустить его как фоновое задание. Затем wait для каждого задания.

Я бы рекомендовал, чтобы у вас было от 2 до 2 * N заданий, отправляющихся одновременно. Где N - количество ядер или логических процессоров на вашем компьютере. Поэкспериментируйте, чтобы получить правильный номер.

Вы можете взломать что-то легкое в BASH.

#!/bin/bash 

argarray=("[email protected]") 
len=${#argarray[@]} 

#declare 4 empty array sets 
set1=() 
set2=() 
set3=() 
set4=() 

# enumerate over each argument passed to the script 
# and round robin add it to one of the above arrays 

i=0 
while [ $i -lt $len ] 
do 

    if [ $i -lt $len ]; then 
     set1+=("${argarray[$i]}") 
     ((i++)) 
    fi 

    if [ $i -lt $len ]; then 
     set2+=("${argarray[$i]}") 
     ((i++)) 
    fi 

    if [ $i -lt $len ]; then 
     set3+=("${argarray[$i]}") 
     ((i++)) 
    fi 

    if [ $i -lt $len ]; then 
     set4+=("${argarray[$i]}") 
     ((i++)) 
    fi 
done 

# for each array, start a background job 
gzip -d ${set1[@]} & 
gzip -d ${set2[@]} & 
gzip -d ${set3[@]} & 
gzip -d ${set4[@]} & 

# wait for all jobs to finish  
wait 

В приведенном выше примере я выбрал 4 файла на одно задание и начал два отдельных задания. Вы можете легко расширить сценарий, чтобы иметь больше заданий, больше файлов для каждого процесса и взять имена файлов в качестве параметров командной строки.

+0

Спасибо за ваш ответ, но я хочу автоматизировать этот процесс. Предположим, у меня есть 50 файлов в моем каталоге, тогда я хочу, чтобы они были распакованы параллельно, чтобы я мог уменьшить время. В настоящее время у меня есть имена файлов со стандартными порядковыми номерами из 01 до 50, поэтому я прохожу первые 10 файлов в одной команде gzip, например мудрый, у меня 5 процессов. Поэтому я хочу создать поток для первых 5 заданий, например мудрый, я могу запустить 10 потоков. Мой вопрос в том, возможно ли это в python? – user3743797

+0

С небольшим количеством скриптов bash вы можете получить это. Преобразуйте параметры командной строки вашего скрипта bash в массив. Затем разделите на 4 отдельных массива. Каждый массив становится отдельным вызовом 'gzip -d'. Я посмотрю, смогу ли я что-нибудь поработать позже ... – selbie

+0

@ user3743797 - теперь это работает. Вы можете вызывать 'script.sh * .gz' или он будет делать именно то, что вы хотите. Я предлагаю иметь сценарий в отдельном каталоге из набора файлов, на которых вы хотите работать. – selbie

8

Вы можете сделать это очень легко с multiprocessing Pools:

import gzip 
import multiprocessing 
import shutil 

filenames = [ 
    'a.gz', 
    'b.gz', 
    'c.gz', 
    ... 
] 

def uncompress(path): 
    with gzip.open(path, 'rb') as src, open(path.rstrip('.gz'), 'wb') as dest: 
     shutil.copyfileobj(src, dest) 

with multiprocessing.Pool() as pool: 
    for _ in pool.imap_unordered(uncompress, filenames, chunksize=1): 
     pass 

Этот код будет порождать несколько процессов, и каждый процесс будет извлекать один файл за раз.

Здесь я выбрал chunksize=1, чтобы избежать процессов сваливания, если некоторые файлы больше среднего.

+0

Привет Андреа, спасибо за ваш ответ. Итак, если я правильно понимаю. Мы обрабатываем 4 файла за раз? если один файл будет завершен, он выберет следующий файл (5-й файл). Пожалуйста, подтвердите. – user3743797

+0

@ user3743797: это правильно –

+0

Спасибо за подтверждение, что если я не хочу жестко кодировать файлы, а не передавать местоположение каталога, чтобы он взял файлы.Метод imap_unordered принимает местоположение каталога как вход для имен файлов? – user3743797

Смежные вопросы