Sebagian besar fungsi Numpy akan mengaktifkan multithreading secara default.
misalnya, saya bekerja pada workstation intel cpu 8-core, jika saya menjalankan skrip
import numpy as np
x=np.random.random(1000000)
for i in range(100000):
np.sqrt(x)
linux top
akan menunjukkan 800% penggunaan CPU selama menjalankan seperti
Yang berarti numpy secara otomatis mendeteksi bahwa workstation saya memiliki 8 core, dan np.sqrt
secara otomatis menggunakan semua 8 core untuk mempercepat perhitungan.
Namun, saya menemukan bug aneh. Jika saya menjalankan skrip
import numpy as np
import pandas as pd
df=pd.DataFrame(np.random.random((10,10)))
df+df
x=np.random.random(1000000)
for i in range(100000):
np.sqrt(x)
penggunaan cpu adalah 100% !!. Ini berarti bahwa jika Anda ditambah dua panda DataFrame sebelum menjalankan fungsi numpy, fitur multithreading otomatis numpy hilang tanpa peringatan! Ini sama sekali tidak masuk akal, mengapa perhitungan dataFrame Pandas memengaruhi pengaturan threading Numpy? Apakah ini bug? Bagaimana cara mengatasinya?
PS:
Saya menggali lebih jauh menggunakan perf
alat Linux .
menjalankan tampilan skrip pertama
Saat menjalankan skrip kedua menunjukkan
Jadi kedua skrip melibatkan libmkl_vml_avx2.so
, sedangkan skrip pertama melibatkan tambahan libiomp5.so
yang tampaknya terkait dengan openMP.
Dan karena vml berarti perpustakaan vektor vektor intel, jadi menurut vml doc saya kira setidaknya fungsi di bawah ini semuanya otomatis multithreaded
import numpy as np import pandas as pd import os os.environ["MKL_NUM_THREADS"] = '4' print(os.environ["MKL_NUM_THREADS"]) df=pd.DataFrame(np.random.random((10,10))) df+df print(os.environ["MKL_NUM_THREADS"]) a = np.random.random((20000000, 3)) b = np.random.random((3, 30)) for _ in range(10): c = np.dot(a, b)
Jawaban:
Panda menggunakan di
numexpr
bawah tenda untuk menghitung beberapa operasi, dannumexpr
menetapkan jumlah maksimal utas untuk vml ke 1, saat diimpor :dan itu diimpor oleh panda saat
df+df
dievaluasi dalam expressions.py :Namun, distribusi Anaconda juga menggunakan vml-fungsi untuk fungsi-fungsi seperti
sqrt
,sin
,cos
dan sebagainya - dan sekalinumexpr
mengatur jumlah maksimal vml-benang ke 1, numpy-fungsi tidak lagi digunakan paralelisasi.Masalahnya dapat dengan mudah dilihat di gdb (menggunakan skrip lambat Anda):
yaitu kita bisa melihat,
numexpr
mengatur jumlah utas ke 1. Yang kemudian digunakan ketika fungsi vml-sqrt disebut:Jadi kita bisa melihat implementasi nml menggunakan nml
vdSqrt
yang digunakanmkl_vml_serv_threader_d_1i_1o
untuk memutuskan apakah perhitungan harus dilakukan secara paralel dan terlihat jumlah utas:register
%rax
memiliki jumlah utas maksimal dan 1.Sekarang kita bisa menggunakan
numexpr
untuk menambah jumlah vml-threads , yaitu:Sekarang banyak core digunakan!
sumber
numexpr
belakang layar.Melihat numpy, sepertinya, di bawah tenda itu memiliki masalah on / off dengan multithreading, dan tergantung pada versi apa yang Anda gunakan, Anda mungkin akan mulai melihat crash ketika Anda bertemu ne.set_vml_num_threads () ..
http://numpy-discussion.10968.n7.nabble.com/ANN-NumExpr-2-7-0-Release-td47414.html
Saya perlu mencari tahu bagaimana ini terpaku pada interpreter python, memberikan contoh kode Anda di mana tampaknya entah bagaimana memungkinkan beberapa panggilan yang tampaknya sinkron / dipesan ke np.sqrt () untuk melanjutkan secara paralel. Saya kira jika interpreter python selalu hanya mengembalikan referensi ke objek ketika muncul tumpukan, dan dalam contoh Anda hanya melempar referensi tersebut dan tidak menetapkan atau memanipulasi mereka dengan cara apa pun itu akan baik-baik saja. Tetapi jika iterasi loop berikutnya tergantung pada yang sebelumnya maka tampaknya kurang jelas bagaimana ini dapat diparalelkan dengan aman. Kegagalan diam-diam / hasil yang salah adalah hasil yang lebih buruk daripada crash.
sumber
Saya pikir premis awal Anda mungkin salah -
Anda menyatakan: Yang berarti numpy secara otomatis mendeteksi bahwa workstation saya memiliki 8 core, dan np.sqrt secara otomatis menggunakan semua 8 core untuk mempercepat perhitungan.
Satu fungsi np.sqrt () tidak dapat menebak bagaimana selanjutnya akan dipanggil atau kembali sebelum sebagian selesai. Ada mekanisme paralelisme dalam python, tetapi tidak ada yang otomatis.
Sekarang, setelah mengatakan itu, interpreter python mungkin dapat mengoptimalkan loop for untuk paralelisme, yang mungkin apa yang Anda lihat, tapi saya sangat curiga jika Anda melihat waktu jam dinding untuk menjalankan loop ini tidak akan ada berbeda terlepas jika Anda (tampaknya) menggunakan 8 core atau 1 core.
UPDATE: Setelah membaca sedikit lebih banyak komentar, sepertinya perilaku multi-core yang Anda lihat terkait dengan distribusi anaconda dari interpreter python. Saya melihat tetapi tidak dapat menemukan kode sumber untuk itu, tetapi tampaknya lisensi python mengizinkan entitas (seperti anaconda.com) untuk mengkompilasi dan mendistribusikan turunan dari juru bahasa tanpa mengharuskan perubahan mereka untuk dipublikasikan.
Saya kira Anda dapat menjangkau orang-orang anaconda - perilaku yang Anda lihat akan sulit untuk dipecahkan tanpa mengetahui apa / jika ada sesuatu yang telah mereka ubah pada penerjemah.
Juga lakukan pemeriksaan cepat dari waktu jam dinding dengan / tanpa optimasi untuk melihat apakah memang 8x lebih cepat - bahkan jika Anda benar-benar memiliki semua 8 core bekerja, bukan 1 akan lebih baik untuk mengetahui apakah hasilnya benar-benar 8x lebih cepat atau jika ada spinlocks yang digunakan yang masih bersambung pada satu mutex.
sumber