2015-12-07 4 views
4

Я пытаюсь использовать joblib в python для ускорения обработки некоторых данных, но у меня возникают проблемы с попыткой определить, как назначить вывод в требуемый формат. Я пытался произвести, возможно, слишком упрощенно, код, который показывает проблемы, которые Я сталкиваюсь:Доступ к глобальному массиву с использованием python joblib

from joblib import Parallel, delayed 
import numpy as np 

def main(): 
    print "Nested loop array assignment:" 
    regular() 
    print "Parallel nested loop assignment using a single process:" 
    par2(1) 
    print "Parallel nested loop assignment using multiple process:" 
    par2(2) 

def regular(): 
    # Define variables 
    a = [0,1,2,3,4] 
    b = [0,1,2,3,4] 
    # Set array variable to global and define size and shape 
    global ab 
    ab = np.zeros((2,np.size(a),np.size(b))) 

    # Iterate to populate array 
    for i in range(0,np.size(a)): 
     for j in range(0,np.size(b)): 
      func(i,j,a,b) 

    # Show array output 
    print ab 

def par2(process): 
    # Define variables 
    a2 = [0,1,2,3,4] 
    b2 = [0,1,2,3,4] 
    # Set array variable to global and define size and shape 
    global ab2 
    ab2 = np.zeros((2,np.size(a2),np.size(b2))) 

    # Parallel process in order to populate array 
    Parallel(n_jobs=process)(delayed(func2)(i,j,a2,b2) for i in xrange(0,np.size(a2)) for j in xrange(0,np.size(b2))) 

    # Show array output 
    print ab2 

def func(i,j,a,b): 
    # Populate array 
    ab[0,i,j] = a[i]+b[j] 
    ab[1,i,j] = a[i]*b[j] 

def func2(i,j,a2,b2): 
    # Populate array 
    ab2[0,i,j] = a2[i]+b2[j] 
    ab2[1,i,j] = a2[i]*b2[j] 

# Run script 
main() 

вывод которого выглядит следующим образом:

Nested loop array assignment: 
[[[ 0. 1. 2. 3. 4.] 
    [ 1. 2. 3. 4. 5.] 
    [ 2. 3. 4. 5. 6.] 
    [ 3. 4. 5. 6. 7.] 
    [ 4. 5. 6. 7. 8.]] 

[[ 0. 0. 0. 0. 0.] 
    [ 0. 1. 2. 3. 4.] 
    [ 0. 2. 4. 6. 8.] 
    [ 0. 3. 6. 9. 12.] 
    [ 0. 4. 8. 12. 16.]]] 
Parallel nested loop assignment using a single process: 
[[[ 0. 1. 2. 3. 4.] 
    [ 1. 2. 3. 4. 5.] 
    [ 2. 3. 4. 5. 6.] 
    [ 3. 4. 5. 6. 7.] 
    [ 4. 5. 6. 7. 8.]] 

[[ 0. 0. 0. 0. 0.] 
    [ 0. 1. 2. 3. 4.] 
    [ 0. 2. 4. 6. 8.] 
    [ 0. 3. 6. 9. 12.] 
    [ 0. 4. 8. 12. 16.]]] 
Parallel nested loop assignment using multiple process: 
[[[ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.]] 

[[ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.] 
    [ 0. 0. 0. 0. 0.]]] 

От Google и StackOverflow функции поиска что при использовании joblib глобальный массив не используется совместно между каждым подпроцессом. Я не уверен, что это ограничение joblib или если есть способ обойти это?

В действительности мой сценарий окружен другими битами кода, которые зависят от конечного выхода этого глобального массива, находящегося в (4, х, х) формата, где х переменные (но обычно находится в диапазоне от 100 до нескольких тысяч). Это моя текущая причина глядя на параллельной обработке, весь процесс может занять до 2-х часов для х = 2400.

Использование joblib не является необходимым (но мне нравится номенклатура и простота), поэтому чувствуют свободно предлагать простые альтернативные методы, в идеале учитывающие требования конечного массива. Я использую python 2.7.3 и joblib 0.7.1.

ответ

4

Я смог решить проблемы с помощью этого простого примера, используя memmap numpy. У меня по-прежнему возникали проблемы после использования memmap и после примеров на joblib documentation webpage, но я обновился до последней версии joblib (0.9.3) через pip, и все это выполняется гладко. Вот рабочий код:

from joblib import Parallel, delayed 
import numpy as np 
import os 
import tempfile 
import shutil 

def main(): 

    print "Nested loop array assignment:" 
    regular() 

    print "Parallel nested loop assignment using numpy's memmap:" 
    par3(4) 

def regular(): 
    # Define variables 
    a = [0,1,2,3,4] 
    b = [0,1,2,3,4] 

    # Set array variable to global and define size and shape 
    global ab 
    ab = np.zeros((2,np.size(a),np.size(b))) 

    # Iterate to populate array 
    for i in range(0,np.size(a)): 
     for j in range(0,np.size(b)): 
      func(i,j,a,b) 

    # Show array output 
    print ab 

def par3(process): 

    # Creat a temporary directory and define the array path 
    path = tempfile.mkdtemp() 
    ab3path = os.path.join(path,'ab3.mmap') 

    # Define variables 
    a3 = [0,1,2,3,4] 
    b3 = [0,1,2,3,4] 

    # Create the array using numpy's memmap 
    ab3 = np.memmap(ab3path, dtype=float, shape=(2,np.size(a3),np.size(b3)), mode='w+') 

    # Parallel process in order to populate array 
    Parallel(n_jobs=process)(delayed(func3)(i,a3,b3,ab3) for i in xrange(0,np.size(a3))) 

    # Show array output 
    print ab3 

    # Delete the temporary directory and contents 
    try: 
     shutil.rmtree(path) 
    except: 
     print "Couldn't delete folder: "+str(path) 

def func(i,j,a,b): 
    # Populate array 
    ab[0,i,j] = a[i]+b[j] 
    ab[1,i,j] = a[i]*b[j] 

def func3(i,a3,b3,ab3): 
    # Populate array 
    for j in range(0,np.size(b3)): 
     ab3[0,i,j] = a3[i]+b3[j] 
     ab3[1,i,j] = a3[i]*b3[j] 

# Run script 
main() 

Давать следующие результаты:

Nested loop array assignment: 
[[[ 0. 1. 2. 3. 4.] 
    [ 1. 2. 3. 4. 5.] 
    [ 2. 3. 4. 5. 6.] 
    [ 3. 4. 5. 6. 7.] 
    [ 4. 5. 6. 7. 8.]] 

[[ 0. 0. 0. 0. 0.] 
    [ 0. 1. 2. 3. 4.] 
    [ 0. 2. 4. 6. 8.] 
    [ 0. 3. 6. 9. 12.] 
    [ 0. 4. 8. 12. 16.]]] 
Parallel nested loop assignment using numpy's memmap: 
[[[ 0. 1. 2. 3. 4.] 
    [ 1. 2. 3. 4. 5.] 
    [ 2. 3. 4. 5. 6.] 
    [ 3. 4. 5. 6. 7.] 
    [ 4. 5. 6. 7. 8.]] 

[[ 0. 0. 0. 0. 0.] 
    [ 0. 1. 2. 3. 4.] 
    [ 0. 2. 4. 6. 8.] 
    [ 0. 3. 6. 9. 12.] 
    [ 0. 4. 8. 12. 16.]]] 

несколько моих мыслей отметить для будущих читателей:

  • На небольших массивов, время, потраченное для подготовки параллельной среды (обычно называемый служебными) означает, что это работает медленнее, чем простой цикл.
  • Сравнение большего массива, например. установка и а3 к np.arange(0,10000) и б и b3 к np.arange(0,1000) дала времен 12.4s для «обычной» методы и 7.7s для joblib метода.
  • Накладные расходы означали, что было бы быстрее разрешить каждому ядру внутренний j цикл (см. Func3). Это имеет смысл, так как я всего лишь , начиная с 10 000 процессов, а не начиная с 10 000 000
    Процессы, каждый из которых нуждается в настройке.