2017-01-25 4 views
1

Я создаю несколько сценариев, чтобы помочь импортировать мою базу данных при использовании докеров. В настоящее время у меня есть каталог, заполненный данными, и я хочу импортировать его как можно быстрее.Многопоточность цикла for в python

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

Это делается с помощью этого кода, который я написал.

#!/usr/bin/python 
import sys 
import subprocess 

cities = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; 

for x in cities: 
    dockerscript = "docker exec -it worker_1 perl import.pl ./public/%s %s mariadb" % (x,x) 
    p = subprocess.Popen(dockerscript, shell=True, stderr=subprocess.PIPE) 

Это работает отлично, если у меня более 10 ядер, каждый из которых имеет свои собственные. То, что я хочу сделать, это настроить его, поэтому, если у меня есть 4 ядра, первые 4 итерации док-скриптов выполняются, от 1 до 4 и от 5 до 10 ждут.

Как только какой-либо из 1 до 4 завершается, начинается 5 и так далее, пока все не будет завершено.

Я просто иметь трудное время выяснить, как сделать это Python

Благодаря

ответ

1

У Иоанна есть ответ, но есть несколько тонкостей, о которых стоит упомянуть. Пул потоков отлично подходит для этого приложения, потому что поток просто тратит свое время на блокировку, ожидая завершения подпроцесса. И вы можете использовать map с chunksize=1, чтобы пул возвращался к родительскому, чтобы получить новое задание на каждой итерации.

#!/usr/bin/python 
import sys 
import subprocess 
import multiprocessing.pool 

cities = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] 

def run_docker(city): 
    return subprocess.call(['docker', 'exec', '-it', 'worker_1', 'perl', 
     'import.pl', './public/{0}'.format(city), city, 'mariadb']) 

pool = multiprocessing.pool.ThreadPool() 
results = pool.map(run_docker, cities, chunksize=1) 
pool.close() 
pool.join() 
+0

Так между Джоном отвечает, что такое карта, а chunksize = 1 делает это, просто используя mutiprocessing.Pool() не выполняет? –

+0

Вы можете использовать 'multiprocessing.Pool' одинаково хорошо, за исключением того, что у него больше накладных расходов. Для linux, его 'fork' и для windows - это exec нового процесса python плюс травление контекста, необходимого для запуска. Затем ввод/вывод должен быть подключен между процессами. – tdelaney

2

Вы должны использовать multiprocessing.Pool(), который будет автоматически создавать один процесс для каждого ядра, а затем представить свои работы на него. Каждое задание будет функцией, которая вызывает subprocess, чтобы запустить Docker. Обратите внимание, что вам нужно убедиться, что задания синхронны - т. Е. команда Docker не должна возвращаться, прежде чем она будет работать.

+0

С использованием mutiprocessing.Pool() это действительно просто строка замены для подпроцесса. Popen()? Цикл for для x в городах все остается неизменным. –