2015-04-25 33 views
17

Eski sorum [1]'dan sonra, matplotlib'in griddata işlevine çok işlemciyi uygulamak istiyorum. Şebeke verilerini, 4 çekirdeğimin her biri için 4 parçaya bölmek mümkün mü? Performansı artırmak için buna ihtiyacım var.Python - matplotlib griddata için çoklu işleme

import numpy as np 
import matplotlib.mlab as mlab 
import time 

size = 500 

Y = np.arange(size) 
X = np.arange(size) 
x, y = np.meshgrid(X, Y) 
u = x * np.sin(5) + y * np.cos(5) 
v = x * np.cos(5) + y * np.sin(5) 
test = x + y 

tic = time.clock() 

test_d = mlab.griddata(
    x.flatten(), y.flatten(), test.flatten(), x+u, y+v, interp='linear') 

toc = time.clock() 

print 'Time=', toc-tic 
+4

Sana çoklu işlem uygulayabilirsiniz sanmıyorum. belki, bu soru http://stackoverflow.com/q/7424777/566035 yararlıdır? – otterb

+0

Örnek kod sözdizimsel olarak doğru değil. Ne şu satırla yapmak niyetinde mi: Ben kodu sabit + yy' – OYRM

+1

'test = xx, şimdi çalışmalıdır. katkınız için –

cevap

5

Ben numpy sürüm 1.9.1 ve matplotlib sürümü 1.4.2 ile Python 3.4.2 aşağıda örnek kod koştum:

Örneğin, size için farklı değerlerle denemeler, aşağıdaki kodu deneyin 4 fiziksel CPU'lar ile Pro Macbook (yani Mac donanım mimarisi de bazı kullanım durumları için kullanılabilir hale getirir "sanal" CPU, aksine):

: Ben şu sonucu var

import numpy as np 
import matplotlib.mlab as mlab 
import time 
import multiprocessing 

# This value should be set much larger than nprocs, defined later below 
size = 500 

Y = np.arange(size) 
X = np.arange(size) 
x, y = np.meshgrid(X, Y) 
u = x * np.sin(5) + y * np.cos(5) 
v = x * np.cos(5) + y * np.sin(5) 
test = x + y 

tic = time.clock() 

test_d = mlab.griddata(
    x.flatten(), y.flatten(), test.flatten(), x+u, y+v, interp='linear') 

toc = time.clock() 

print('Single Processor Time={0}'.format(toc-tic)) 

# Put interpolation points into a single array so that we can slice it easily 
xi = x + u 
yi = y + v 
# My example test machine has 4 physical CPUs 
nprocs = 4 
jump = int(size/nprocs) 

# Enclose the griddata function in a wrapper which will communicate its 
# output result back to the calling process via a Queue 
def wrapper(x, y, z, xi, yi, q): 
    test_w = mlab.griddata(x, y, z, xi, yi, interp='linear') 
    q.put(test_w) 

# Measure the elapsed time for multiprocessing separately 
ticm = time.clock() 

queue, process = [], [] 
for n in range(nprocs): 
    queue.append(multiprocessing.Queue()) 
    # Handle the possibility that size is not evenly divisible by nprocs 
    if n == (nprocs-1): 
     finalidx = size 
    else: 
     finalidx = (n + 1) * jump 
    # Define the arguments, dividing the interpolation variables into 
    # nprocs roughly evenly sized slices 
    argtuple = (x.flatten(), y.flatten(), test.flatten(), 
       xi[:,(n*jump):finalidx], yi[:,(n*jump):finalidx], queue[-1]) 
    # Create the processes, and launch them 
    process.append(multiprocessing.Process(target=wrapper, args=argtuple)) 
    process[-1].start() 

# Initialize an array to hold the return value, and make sure that it is 
# null-valued but of the appropriate size 
test_m = np.asarray([[] for s in range(size)]) 
# Read the individual results back from the queues and concatenate them 
# into the return array 
for q, p in zip(queue, process): 
    test_m = np.concatenate((test_m, q.get()), axis=1) 
    p.join() 

tocm = time.clock() 

print('Multiprocessing Time={0}'.format(tocm-ticm)) 

# Check that the result of both methods is actually the same; should raise 
# an AssertionError exception if assertion is not True 
assert np.all(test_d == test_m) 

ve

/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/matplotlib/tri/triangulation.py:110: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future.self._neighbors) 
Single Processor Time=8.495998 
Multiprocessing Time=2.249938 

triangulation.py'den "gelecekteki uyarılar" ın neden kaynaklandığını tam olarak bilmiyorum (matplotlib sürümüm, orijinal olarak soru için sağlanan girdi değerleriyle ilgili bir şeyden hoşlanmadı), fakat ne olursa olsun, Çok işlemcili , 4 CPU'lu bir makine için bekleyeceğimiz yaklaşık 4X'lik bir mahallede yaklaşık 8,50/2,25 = 3,8, (düzenleme: bkz. Yorumlar) istenen hıza ulaşmak için görünmüyor. Ve sondaki iddia beyanı da, iki yöntemin aynı cevabı aldığını kanıtlayarak başarılı şekilde yürütür, bu yüzden biraz tuhaf uyarı mesajına rağmen, yukarıdaki kodun geçerli bir çözüm olduğuna inanıyorum.


DÜZENLEME: Bir yorumcu benim çözüm, hem de orijinal yazar tarafından gönderilmiş kod parçacığı hem olasılıkla yürütme zamanı ölçmek için, yanlış bir yöntem, time.clock() kullandığınızı işaret ettiği; Bunun yerine time.time() kullanmayı önerir. Sanırım onun bakış açısına da yaklaşıyorum. (Python belgelerine biraz daha fazla girerek, Python'un daha yeni sürümlerive time.process_time()'un lehine kullanıldığından, bu çözümün bile% 100 doğru olduğuna ikna olmadım. veya time.time() kesinlikle bu ölçümü yapmanın en doğru yoludur, yine de daha önce kullanmış olduğumdan daha doğrudur, time.clock().

Eğer yorumlayıcının noktası doğruysa, o zaman yaklaşık 4X hızlanma anlamına gelir. Ölçdüğüm düşünce aslında yanlış. Bununla birlikte, bu, altta yatan kodun kendisinin doğru olarak paralelleştirilmiş olmadığı anlamına gelmez; daha doğrusu, sadece paralelleşmenin bu durumda yardımcı olmadığı anlamına gelir; Verileri bölmek ve birden çok işlemci üzerinde çalışmak hiçbir şeyi iyileştirmedi. Bu neden olsun ki? Diğer kullanıcılar pointed out, en azından numpy/scipy, bazı işlevler birden fazla çekirdek üzerinde çalışırlar ve bazıları yok, ve son kullanıcı için hangisinin hangisi olduğunu anlamaya çalışmak için çok zorlu bir araştırma projesi olabilir.

Bu denemenin sonuçlarına dayanarak, eğer çözümüm Python içinde paralelleşmeyi doğru bir şekilde gerçekleştiriyorsa, ancak daha fazla hızlanma gözlenmezse, en basit olası açıklama, matplotlib'in muhtemelen bazı işlevlerini de paralel hale getirmesidir. başlık ", yani konuşmak için, derlenmiş C++ kütüphanelerinde, zaten numpy/scipy zaten yapar. Durumun bu olduğunu varsayarsak, o zaman bu sorunun doğru cevabı daha fazla bir şey yapamayacaktır: Python'da daha da paralel hale getirmek, temeldeki C++ kütüphaneleri zaten başlamak üzere birden fazla çekirdek üzerinde sessizce çalışıyorsa iyi olmaz.

+1

Ne yazık ki() '' (http://stackoverflow.com/a/23325328/1510289 bakınız) '' time.clock kullanarak duvar saati süresini hesaplama değiliz. Bunun yerine, 'time.time()' işlevini kullanın ve çoklu işlem senaryosunun gerçekten daha uzun sürdüğünü fark edin. Yine de güzel bir deneme! Ben de giriş değerlerini kendim ayırmayı denedim ve "griddata()" 'ya hiçbir hızlandırma bulunamadı. .. :( –

+1

Üzgünüz ama @ Stachyra cevabı yanlış İkameci '' time.clock() '' time.time() '' gerçek duvar saati performansı kötüdür '' ile My 8-CPU makine veriyor: '' Tek İşlemci "traceback (son en son çağrı): Dosya 'Zaman = 8,833 Multiprocessing Zaman = 11.677'' –

+0

bunu başlatmak olamaz ... ben bir hata var /usr/lib/python2.7/multiprocessing/process.py', satır 258, _bootstrap içinde self._target (* self._args, ** self._kwargs) Dosya "", satır 11, sarmalayıcıda test_w = mlab.griddata (x, y griddata de, z, xi, yi, interp = 'lineer') Dosya "/usr/lib/pymodules/python2.7/matplotlib/mlab.py", hat 2619 ValueError yükseltmek ("çıkış ızgarası sabit bir mesafe olması gerekir " ValueError: çıkış ızgarası sabit sp'ye sahip olmalıdır interp = 'linear' kullanırken acing ... " – user3601754