2017-01-13 2 views
1

у меня есть код питона, который использует пакет подпроцесса для запуска в оболочке:питона распространение subprocess.call на нескольких процессорных ядрах

subprocess.call(mycode.py, shell=inshell) 

Когда я выполнить верхнюю команду, я вижу, что я только использую ~ 30% или меньше CPU. Я понимаю, что некоторые команды могут использовать диск, а не процессор, поэтому я определял скорость. Скорость, выполняемая на Linux-системе, кажется медленнее, чем система с двумя ядрами.

Как я могу распараллелить это с помощью потокового или многопроцессорного пакета, чтобы я мог использовать несколько ядер процессора в указанной Linux-системе?

+0

Вы хотите использовать несколько потоков или процессов, чтобы вы могли выполнять код в 'mycode.py' несколько раз? Или вы хотите выполнить 'mycode.py' только один раз и ускорить его, распараллеливая работу? – FMc

+0

Да, я хочу выполнить mycode.py только один раз, но сделать это быстрее, распараллеливая. –

ответ

0

Небольшое изменение в ответ FMC, в

work_items = [(1, 'A', True), (2, 'X', False), (3, 'B', False)] 
def worker(tup): 
for i in range(5000000): 
    print(work_items) 
return 

pool = Pool(processes = 8) 
start = time.time() 
work_results = pool.map(worker, work_items) 
end = time.time() 
print(end-start) 
pool.close() 
pool.join() 

Код на картинке: 53.60 секунд. Трюк ниже, однако, занимает 27,34 секунды.

from multiprocessing import Pool 
import functools 
import time 

work_items = [(1, 'A', True), (2, 'X', False), (3, 'B', False)] 

def worker(tup): 
    for i in range(5000000): 
     print(work_items) 
    return 

def parallel_attribute(worker): 
    def easy_parallelize(worker, work_items): 
     pool = Pool(processes = 8) 
     work_results = pool.map(worker, work_items) 
     pool.close() 
     pool.join() 
    from functools import partial 
    return partial(easy_parallelize, worker) 

start = time.time() 
worker.parallel = parallel_attribute(worker(work_items)) 
end = time.time() 
print(end - start) 

Два комментария: 1) я не видел большой разницы с использованием многопроцессорных фиктивный 2) С помощью частичной функции Питона (области действия с вложенности) работает как прекрасная обертку, которая уменьшает время вычислений на 1/2. Артикул: https://www.binpress.com/tutorial/simple-python-parallelism/121

Также, спасибо FMc!

0

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

import threading 
import subprocess 

def worker(): 
    """thread worker function""" 
    print 'Worker' 
    subprocess.call(mycode.py, shell=inshell) 
    return 

threads = [] 
for i in range(5): 
    t = threading.Thread(target=worker) 
    threads.append(t) 
    t.start() 
+0

Спасибо, просто интересно: когда вы укажете количество итераций как 5, как определить, какое будет оптимальное число? что определяет, сколько потоков будет распространять функцию subprocess.call? –

+0

Ну, нет правила, которое зависит от использования процессора. Я попробую сначала с 3 потоками, как вы говорите, вы используете ~ 30% от процессора. –

1

Чтобы распараллелить работу в mycode.py, вам нужно организовать код так, что она вписывается в эту основную схему:

# Import the kind of pool you want to use (processes or threads). 
from multiprocessing import Pool 
from multiprocessing.dummy import Pool as ThreadPool 

# Collect work items as an iterable of single values (eg tuples, 
# dicts, or objects). If you can't hold all items in memory, 
# define a function that yields work items instead. 
work_items = [ 
    (1, 'A', True), 
    (2, 'X', False), 
    ... 
] 

# Define a callable to do the work. It should take one work item. 
def worker(tup): 
    # Do the work. 
    ... 

    # Return any results. 
    ... 

# Create a ThreadPool (or a process Pool) of desired size. 
# What size? Experiment. Slowly increase until it stops helping. 
pool = ThreadPool(4) 

# Do work and collect results. 
# Or use pool.imap() or pool.imap_unordered(). 
work_results = pool.map(worker, work_items) 

# Wrap up. 
pool.close() 
pool.join() 

--------------------- 

# Or, in Python 3.3+ you can do it like this, skipping the wrap-up code. 
with ThreadPool(4) as pool: 
    work_results = pool.map(worker, work_items) 
+0

Здесь следует упомянуть различные варианты использования для пулов процессов и пулов потоков, учитывая влияние GIL на потоки CPython. –

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