Q1 :
" why the kernel keeps busy, but I did not see 4 workers from windows task manager? "
A1 :
让我们在代码本身中解决这个问题:
import os
import time
...
def fuc( sig ):
print( ( "INF[{0:}]: fuc() starts "
+ "running in process[{1:}]"
+ "-called-from-process[{2:}]"
).format( time.get_perf_ns(), os.getpid(), os.getppid() )
)
C = fft( sig, axis = -1 )
print( ( "INF[{0:}]: fuc() FFT done "
+ "running in process[{1:}]"
+ "-called-from-process[{2:}]"
).format( time.get_perf_ns(), os.getpid(), os.getppid() )
)
return C
该代码将自行记录实际计算计划的 FFT 部分的时间、内容和时间。
Q2 :
" do I use the right way to get parallel calculated results in line "FKP = list(results)"? "
A2 :
是的,但是每个 SER/COMMS/DES 进程到进程边界的跨越都会产生一系列显着的附加开销成本,其中所有数据都进行 SER/DES 编码(pickle.dumps()
-CPU/RAM 成本相同[TIME]-
+ [SPACE]-
域 + 非零 ipc-p2p-传输时间 ) :
def Pinf():
print( ( "NEW[{0:}]: ProcessPoolExecutor process-pool has "
+ "started process[{1:}]"
+ "-called-from-process[{2:}]"
).format( time.get_perf_ns(), os.getpid(), os.getppid() )
)
def main():
...
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print( ( "INF[{0:}]: context-manager"
+ 30*"_" + " entry point"
).format( time.get_perf_ns()
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
with concurrent.futures.ProcessPoolExecutor( max_workers = 4,
initializer = Pinf
) as ex:
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print( ( "INF[{0:}]: context-manager"
+ " is to start .map()"
).format( time.get_perf_ns()
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
results = ex.map( fuc,
( fkp[p,m].reshape( 1, K )
for p in range( P )
for m in range( M )
)
)
...
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print( ( "INF[{0:}]: context-manager"
+ " .map() returned / __main__ has received all <_results_>"
).format( time.get_perf_ns()
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pass
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print( ( "INF[{0:}]: context-manager"
+ 30*"_" + " exited"
).format( time.get_perf_ns()
)
...
print( type( results ) )
...
有关每个进程池进程实例化的实际附加成本,请参阅报告的 ns-traces。详细信息是特定于平台的,如 { MacOS | Linux | Windows }-产生新进程的方法有很大不同。这同样适用于 Python 版本,因为较新的 Py3 版本在调用 Python 解释器进程复制方面做得很好,这与 Py2 和早期版本的 Py3.x 中常见的情况不同 - 有些复制调用 Python 的整个有状态副本-解释器,具有数据、文件描述符等的完整副本 - 由于所有关联的 RAM 分配用于存储调用 Python 解释器的 n 个副本,因此承受更大的进程实例化成本。
考虑到缩放比例:
>>> len( [ ( p, m ) for p in range( P ) for m in range( M ) ] )
600
效率很重要。仅将带有子范围索引的一个元组(p_start,p_end,m_start,m_end)传递给4个进程,其中应进行信号部分的FFT处理并返回其FFT结果的子列表,将避免传递相同的静态数据以小块形式多次传输,完全避免 596x 通过(CPU-RAM 和延迟方面)昂贵的 SER/COMMS/DES-SED/COMMS/DES ipc-p2p 数据传递通道。
欲了解更多详细信息,您可能想重新阅读this https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor and this https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods.