T. *_*ter 18 python parallel-processing python-2.7
我正在尝试使用Python进行多处理器编程.Fibonacci例如,采用分治算法.程序流程的执行将像树一样分支并并行执行.换句话说,我们有一个嵌套并行性的例子.
从Java开始,我使用线程池模式来管理资源,因为程序可以非常快速地扩展并创建太多短期线程.可以通过实例化单个静态(共享)线程池 ExecutorService.
我希望Pool也一样,但看起来Pool对象不是全局共享的.例如,使用共享池multiprocessing.Manager.Namespace()将导致错误.
池对象不能在进程之间传递或被pickle
我有一个由两部分组成的问题:
from concurrent.futures import ThreadPoolExecutor
def fibonacci(n):
if n < 2:
return n
a = pool.submit(fibonacci, n - 1)
b = pool.submit(fibonacci, n - 2)
return a.result() + b.result()
def main():
global pool
N = int(10)
with ThreadPoolExecutor(2**N) as pool:
print(fibonacci(N))
main()
Run Code Online (Sandbox Code Playgroud)
Java的
public class FibTask implements Callable<Integer> {
public static ExecutorService pool = Executors.newCachedThreadPool();
int arg;
public FibTask(int n) {
this.arg= n;
}
@Override
public Integer call() throws Exception {
if (this.arg > 2) {
Future<Integer> left = pool.submit(new FibTask(arg - 1));
Future<Integer> right = pool.submit(new FibTask(arg - 2));
return left.get() + right.get();
} else {
return 1;
}
}
public static void main(String[] args) throws Exception {
Integer n = 14;
Callable<Integer> task = new FibTask(n);
Future<Integer> result =FibTask.pool.submit(task);
System.out.println(Integer.toString(result.get()));
FibTask.pool.shutdown();
}
}
Run Code Online (Sandbox Code Playgroud)
我不确定这里是否重要,但我忽略了"过程"和"线程"之间的区别; 对我来说,他们都意味着"虚拟处理器".我的理解是,池的目的是共享"池"或资源.运行任务可以向池发出请求.当并行任务在其他线程上完成时,可以回收这些线程并将其分配给新任务.禁止共享池是没有意义的,因此每个线程必须实例化自己的新池,因为这似乎会破坏线程池的目的.
1)我在这里缺少什么;为什么进程之间不应该共享池?
并非所有对象/实例都是可选取/可序列化的,在这种情况下,池使用不可选取的 threading.lock:
>>> import threading, pickle
>>> pickle.dumps(threading.Lock())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
[...]
File "/Users/rafael/dev/venvs/general/bin/../lib/python2.7/copy_reg.py", line 70, in _reduce_ex
raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle lock objects
Run Code Online (Sandbox Code Playgroud)
或更好:
>>> import threading, pickle
>>> from concurrent.futures import ThreadPoolExecutor
>>> pickle.dumps(ThreadPoolExecutor(1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps
Pickler(file, protocol).dump(obj)
File
[...]
"/usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save
rv = reduce(self.proto)
File "/Users/rafael/dev/venvs/general/bin/../lib/python2.7/copy_reg.py", line 70, in _reduce_ex
raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle lock objects
Run Code Online (Sandbox Code Playgroud)
如果你仔细想想,这是有道理的,锁是由操作系统管理的信号量原语(因为Python使用本机线程)。能够在 python 运行时中 pickle 并保存该对象状态实际上不会完成任何有意义的事情,因为它的真实状态是由操作系统保存的。
2)Python中实现嵌套并行的模式是什么?如果可能的话,保持递归结构,而不是用它来换取迭代
现在,为了名誉,我上面提到的所有内容并不真正适用于您的示例,因为您使用的是线程(ThreadPoolExecutor)而不是进程(ProcessPoolExecutor),因此不必发生跨进程的数据共享。
您的java示例似乎更高效,因为您使用的线程池(CachedThreadPool)正在根据需要创建新线程,而python执行器实现是有限的并且需要显式的最大线程计数(max_workers)。这两种语言之间存在一些语法差异,这似乎也会让你感到困惑(Python 中的静态实例本质上是任何没有明确作用域的东西),但本质上这两个示例都会创建完全相同数量的线程来执行。例如,下面是一个在 python 中使用相当简单的 CachedThreadPoolExecutor 实现的示例:
from concurrent.futures import ThreadPoolExecutor
class CachedThreadPoolExecutor(ThreadPoolExecutor):
def __init__(self):
super(CachedThreadPoolExecutor, self).__init__(max_workers=1)
def submit(self, fn, *args, **extra):
if self._work_queue.qsize() > 0:
print('increasing pool size from %d to %d' % (self._max_workers, self._max_workers+1))
self._max_workers +=1
return super(CachedThreadPoolExecutor, self).submit(fn, *args, **extra)
pool = CachedThreadPoolExecutor()
def fibonacci(n):
print n
if n < 2:
return n
a = pool.submit(fibonacci, n - 1)
b = pool.submit(fibonacci, n - 2)
return a.result() + b.result()
print(fibonacci(10))
Run Code Online (Sandbox Code Playgroud)
性能调整:
我强烈建议研究gevent,因为它会为您提供高并发性而无需线程开销。情况并非总是如此,但您的代码实际上是 gevent 使用的典型代表。这是一个例子:
import gevent
def fibonacci(n):
print n
if n < 2:
return n
a = gevent.spawn(fibonacci, n - 1)
b = gevent.spawn(fibonacci, n - 2)
return a.get() + b.get()
print(fibonacci(10))
Run Code Online (Sandbox Code Playgroud)
完全不科学,但在我的计算机上,上面的代码运行速度比其线程等效代码快9 倍。
我希望这有帮助。
| 归档时间: |
|
| 查看次数: |
6537 次 |
| 最近记录: |