Пытаюсь освоить выгоду от исползования multi-core CPU + python.
Сразу скажу, про GIL читал вскользь.
Сначала опробывал синтаксис исползуя простенький примерчик, где в отделных процессах запускалась функция совершающая много несвязанных арифметических действий.
from multiprocessing import Process, Pool
import os, time
def f(arg):
mas = range(1, 10000)
p = 1
for i in mas:
p*=i*i*i*i
print 'parent process:', os.getppid(), 'process id:', os.getpid()
print "calculation", arg, "DONE"
if __name__ == '__main__':
t = time.time()
case = 2
if case == 0:
print 'POOL, 4x parallel calculation'
pool = Pool(processes = 4) # start 4 worker processes
pool.map(f, [1,2,3,4])
if case == 1:
print '4x parallel calculation'
p1 = Process(target=f, args=(1,))
p1.start()
p2 = Process(target=f, args=(2,))
p2.start()
p3 = Process(target=f, args=(3,))
p3.start()
p4 = Process(target=f, args=(4,))
p4.start()
p1.join()
p2.join()
p3.join()
p4.join()
if case == 2:
print 'serial calculation'
f(1)
f(2)
f(3)
f(4)
print "Time taken:", time.time() - t
Пример показал позитивный эффект даже на слабеньком процессоре Athom с технологией Hyper Threading.
case 1:
4x parallel calculation
parent process: 24640 process id: 24643
calculation 3 DONE
parent process: 24640 process id: 24642
calculation 2 DONE
parent process: 24640 process id: 24641
calculation 1 DONE
parent process: 24640 process id: 24644
calculation 4 DONE
Time taken: 17.3200678825
serial calculation
parent process: 24649 process id: 24651
calculation 1 DONE
parent process: 24649 process id: 24651
calculation 2 DONE
parent process: 24649 process id: 24651
calculation 3 DONE
parent process: 24649 process id: 24651
calculation 4 DONE
Time taken: 27.8628590107
from multiprocessing import Process, Queue
import os, time
from random import randint
def f1(list1, list2):
for l1 in list1:
for l2 in list2:
if l1.xy == l2.xy:
list1.remove(l1)
list2.remove(l2)
break
#return list1, list2
def f2(list1, list2):
for l1 in list1:
l1.render()
for l2 in list2:
l2.render()
class ob():
def __init__(self, (x,y)):
self.xy = (x,y)
def render(self):
(x, y) = self.xy ; x*x*x*x*x*x*x # some load
if __name__ == '__main__':
case = 0
npc_list = []
bullets_list = []
npc_list2 = []
bullets_list2 = []
i = 0
while i < 1000:
npc = ob((randint(1,100), randint(1,100)))
npc_list.append(npc)
bullet = ob((randint(1,100), randint(1,100)))
bullets_list.append(bullet)
npc = ob((randint(1,100), randint(1,100)))
npc_list2.append(npc)
bullet = ob((randint(1,100), randint(1,100)))
bullets_list2.append(bullet)
i += 1
while True:
t = time.time()
if case == 0:
print "PARALLEL calc. using SAME objects"
p1 = Process(target=f1, args=(npc_list, bullets_list))
p1.start()
p2 = Process(target=f2, args=(npc_list, bullets_list))
p2.start()
p1.join()
p2.join()
if case == 1:
print "PARALLEL calc. using DIFFERENT objects"
p1 = Process(target=f1, args=(npc_list, bullets_list))
p1.start()
p2 = Process(target=f2, args=(npc_list2, bullets_list2))
p2.start()
p1.join()
p2.join()
if case == 2:
print "SERIAL calc."
f1(npc_list, bullets_list)
f2(npc_list, bullets_list)
print "Time taken:", time.time() - t
PARALLEL calc. using SAME objects
Time taken: 1.75695300102
Time taken: 1.71754407883
Time taken: 1.72614192963
PARALLEL calc. using DIFFERENT objects
Time taken: 1.70828604698
Time taken: 1.69986701012
Time taken: 1.74617981911
SERIAL calc.
Time taken: 1.66356611252
Time taken: 0.824527978897
Time taken: 0.73535490036
Time taken: 0.86488699913
Time taken: 0.710259914398
Как бы мне лучше поступить?
Кстати создание процессов внутри loop мой недочёт, позже я подумаю как это дело вынести за пределы loop ( в моём случае это game-loop), просто сейчас хочу нащупать основной эффект, а допилка и дооптимизация планируется после.
Зараннее благодарю.