Python 我在这里做多核编程对吗
我希望有一些守护程序,可以找到需要转换为web和thumb版本的图像。我认为python在这里可能有用,但我不确定我是否在这里做事情。我想同时转换8张照片,要转换的图像队列可能很长。我们在服务器上有几个内核,在一个新的进程中生成每个转换应该让操作系统利用可用的内核,事情会发展得更快,对吗?这是这里的关键点,从python生成一个进程,再次调用imagemagick的转换脚本,并希望事情比从python主线程运行一对一转换快一点 到目前为止,我只是开始测试。这是我的测试代码。它将创建20个任务(睡眠时间为1到5秒),并将这些任务分配给总共有5个线程的池Python 我在这里做多核编程对吗,python,multithreading,process,multicore,Python,Multithreading,Process,Multicore,我希望有一些守护程序,可以找到需要转换为web和thumb版本的图像。我认为python在这里可能有用,但我不确定我是否在这里做事情。我想同时转换8张照片,要转换的图像队列可能很长。我们在服务器上有几个内核,在一个新的进程中生成每个转换应该让操作系统利用可用的内核,事情会发展得更快,对吗?这是这里的关键点,从python生成一个进程,再次调用imagemagick的转换脚本,并希望事情比从python主线程运行一对一转换快一点 到目前为止,我只是开始测试。这是我的测试代码。它将创建20个任务(睡
from multiprocessing import Process
from subprocess import call
from random import randrange
from threading import Thread
from Queue import Queue
class Worker(Thread):
def __init__(self, tid, queue):
Thread.__init__(self)
self.tid = tid
self.queue = queue
self.daemon = True
self.start()
def run(self):
while True:
sec = self.queue.get()
print "Thread %d sleeping for %d seconds\n\n" % (self.tid, sec)
p = Process(target=work, args=(sec,))
p.start()
p.join()
self.queue.task_done()
class WorkerPool:
def __init__(self, num_workers):
self.queue = Queue()
for tid in range(num_workers):
Worker(tid, self.queue)
def add_task(self, sec):
self.queue.put(sec)
def complete_work(self):
self.queue.join()
def work(sec):
call(["sleep", str(sec)])
def main():
seconds = [randrange(1, 5) for i in range(20)]
pool = WorkerPool(5)
for sec in seconds:
pool.add_task(sec)
pool.complete_work()
if __name__ == '__main__':
main()
因此,我在服务器上运行此脚本:
johanhar@mamadev:~$ python pythonprocesstest.py
johanhar@mamadev:~$ ps -fux
然后我检查服务器上的进程:
johanhar@mamadev:~$ python pythonprocesstest.py
johanhar@mamadev:~$ ps -fux
ps
的结果在我看来是错误的。在我看来,在python下似乎发生了一些事情,但是在一个进程中发生了一些事情,因此即使服务器上有多个内核,转换次数越多(或者像本测试案例中那样休眠),转换速度也只会越慢
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
johanhar 24246 0.0 0.0 81688 1608 ? S 13:44 0:00 sshd: johanhar@pts/28
johanhar 24247 0.0 0.0 108336 1832 pts/28 Ss 13:44 0:00 \_ -bash
johanhar 49753 0.6 0.0 530620 7512 pts/28 Sl+ 15:14 0:00 \_ python pythonprocesstest.py
johanhar 49822 0.0 0.0 530620 6252 pts/28 S+ 15:14 0:00 \_ python pythonprocesstest.py
johanhar 49824 0.0 0.0 100904 564 pts/28 S+ 15:14 0:00 | \_ sleep 4
johanhar 49823 0.0 0.0 530620 6256 pts/28 S+ 15:14 0:00 \_ python pythonprocesstest.py
johanhar 49826 0.0 0.0 100904 564 pts/28 S+ 15:14 0:00 | \_ sleep 3
johanhar 49837 0.0 0.0 530620 6264 pts/28 S+ 15:14 0:00 \_ python pythonprocesstest.py
johanhar 49838 0.0 0.0 100904 564 pts/28 S+ 15:14 0:00 | \_ sleep 3
johanhar 49846 0.0 0.0 530620 6264 pts/28 S+ 15:14 0:00 \_ python pythonprocesstest.py
johanhar 49847 0.0 0.0 100904 564 pts/28 S+ 15:14 0:00 \_ sleep 3
所以如果你还是不明白我的问题或者我的要求。这种方法可以称为“多核编程”吗?我认为您误读了
ps
输出。我统计了4个不同的Python实例,每个实例原则上都可以分配给自己的核心。他们是否真的拥有自己的内核是多重处理中比较困难的一点
是的,有一个高级Python进程(PID 49753),它是子进程的父进程,但也有一个
bash
,它以类似的方式是子进程的父进程 我认为您误读了ps
输出。我统计了4个不同的Python实例,每个实例原则上都可以分配给自己的核心。他们是否真的拥有自己的内核是多重处理中比较困难的一点
是的,有一个高级Python进程(PID 49753),它是子进程的父进程,但也有一个
bash
,它以类似的方式是子进程的父进程 Short&direct:是的,您正在多核上运行多个convert
进程
更长&稍微间接:我不会称之为“多核编程”,即使它实际上是,因为这种措辞通常意味着在多核上运行程序的多个线程,而您没有这样做(至少在CPython中,python线程受GIL约束,不能在多核上同时运行)。此外,您不需要并行化python代码,因为这不是您的瓶颈(您将时间花在convert
上,而不是用python代码)
如果您只想并行化转换,那么在python代码中甚至不需要任何线程或其他花哨的东西
python脚本可以被序列化并在照片中循环,生成新的转换过程,直到达到所需的数量。然后就坐在那里,等待其中一个完成并产生一个新的;根据需要对所有照片重复此操作
(但我同意线程比那种等待事件循环更自然、更优雅)简短和直接:是的,您正在多核上运行多个convert
进程
更长&稍微间接:我不会称之为“多核编程”,即使它实际上是,因为这种措辞通常意味着在多核上运行程序的多个线程,而您没有这样做(至少在CPython中,python线程受GIL约束,不能在多核上同时运行)。此外,您不需要并行化python代码,因为这不是您的瓶颈(您将时间花在convert
上,而不是用python代码)
如果您只想并行化转换,那么在python代码中甚至不需要任何线程或其他花哨的东西
python脚本可以被序列化并在照片中循环,生成新的转换过程,直到达到所需的数量。然后就坐在那里,等待其中一个完成并产生一个新的;根据需要对所有照片重复此操作
(但我同意线程比等待事件循环更自然、更优雅)您可以简化代码。如果工作是在子进程中完成的,则不需要多个Python进程。您可以使用多处理.Pool
来限制并发子进程的数量:
#!/usr/bin/env python
import multiprocessing.dummy as mp # use threads
from random import randrange
from subprocess import check_call
from timeit import default_timer as timer
def info(msg, _print_lock=mp.Lock()): # a poor man's logging.info()
with _print_lock: # avoid garbled output
print("%s\t%s" % (mp.current_process().name, msg))
def work(sec):
try: # wrap in try/except to avoid premature exit
info("Sleeping for %d seconds" % (sec,))
start = timer()
check_call(["sleep", str(sec)])
except Exception as e: # error
return sec, timer() - start, e
else: # success
return sec, timer() - start, None
def main():
work_items = (randrange(1, 5) for i in range(20)) # you can use generator
pool = mp.Pool(5) # pool of worker threads
for result in pool.imap_unordered(work, work_items):
info("expected %s, got %s, error %s" % result)
pool.close()
pool.join()
if __name__ == '__main__':
main()
输出
您可以简化代码。如果工作是在子进程中完成的,则不需要多个Python进程。您可以使用多处理.Pool
来限制并发子进程的数量:
#!/usr/bin/env python
import multiprocessing.dummy as mp # use threads
from random import randrange
from subprocess import check_call
from timeit import default_timer as timer
def info(msg, _print_lock=mp.Lock()): # a poor man's logging.info()
with _print_lock: # avoid garbled output
print("%s\t%s" % (mp.current_process().name, msg))
def work(sec):
try: # wrap in try/except to avoid premature exit
info("Sleeping for %d seconds" % (sec,))
start = timer()
check_call(["sleep", str(sec)])
except Exception as e: # error
return sec, timer() - start, e
else: # success
return sec, timer() - start, None
def main():
work_items = (randrange(1, 5) for i in range(20)) # you can use generator
pool = mp.Pool(5) # pool of worker threads
for result in pool.imap_unordered(work, work_items):
info("expected %s, got %s, error %s" % result)
pool.close()
pool.join()
if __name__ == '__main__':
main()
输出
谢谢:)我想如果有4-5个转换,或者只有1个转换,最好是进行一些转换并签入top
。对于这样的进程和操作系统,我真的是个新手。谢谢:)我想如果有4-5个或者只有1个,最好是进行一些转换,然后签入top
。说到进程和操作系统之类的东西,我真的是个新手。ps输出只是显示您有一个父根python进程,它派生了4个子进程。这并不意味着一切都在一个进程内运行。显示的树只是父子关系。我不知道是否有一种方法可以在python中手动设置CPU内核之间的关联性,因此,通过这种方式,我们假设操作系统负责内核之间进程的分布。我发现了一个有趣的库,它可以帮助您跟踪进程在内核之间的分布情况。这里是-看看get\u cpu\u affinity()set\u cpu\u affinity()功能。顺便说一句,我仍然坚持这个建议