我正在使用Yelp中的(真棒)mrjob库在Amazon的Elastic Map Reduce中运行我的python程序。它取决于标准python库中的子进程。从我的mac运行python2.7.2,一切都按预期工作
但是,当我在使用python2.7.2的Ubuntu LTS 11.04上使用完全相同的代码时,我遇到了一些奇怪的事情:
mrjob加载作业,然后尝试使用子进程与其子进程通信并生成此错误:
File "/usr/local/lib/python2.7/dist-packages/mrjob-0.3.1-py2.7.egg/mrjob/emr.py", line 1212, in _build_steps steps = self._get_steps() File "/usr/local/lib/python2.7/dist-packages/mrjob-0.3.1-py2.7.egg/mrjob/runner.py", line 1003, in _get_steps stdout, stderr = steps_proc.communicate() File "/usr/lib/python2.7/subprocess.py", line 754, in communicate return self._communicate(input) File "/usr/lib/python2.7/subprocess.py", line 1302, in _communicate stdout, stderr = self._communicate_with_poll(input) File "/usr/lib/python2.7/subprocess.py", line 1332, in _communicate_with_poll poller = select.poll() AttributeError: 'module' object has no attribute 'poll'
这似乎是子进程的问题,而不是mrjob。
我挖到/usr/lib/python2.7/subprocess.py并发现在导入过程中它运行:
if mswindows: ... snip ... else: import select _has_poll = hasattr(select, 'poll')
通过编辑,我确认它确实设置了_has_poll == True。这是正确的;在命令行上轻松验证。
然而,当执行过程以某种方式使用Popen._communicate_with_poll时,选择模块已经改变了!这是通过在尝试使用select.poll()之前打印dir(select)生成的。
['EPOLLERR', 'EPOLLET', 'EPOLLHUP', 'EPOLLIN', 'EPOLLMSG', 'EPOLLONESHOT', 'EPOLLOUT', 'EPOLLPRI', 'EPOLLRDBAND', 'EPOLLRDNORM', 'EPOLLWRBAND', 'EPOLLWRNORM', 'PIPE_BUF', 'POLLERR', 'POLLHUP', 'POLLIN', 'POLLMSG', 'POLLNVAL', 'POLLOUT', 'POLLPRI', 'POLLRDBAND', 'POLLRDNORM', 'POLLWRBAND', 'POLLWRNORM', '__doc__', '__name__', '__package__', 'error', 'select']
没有名为'民意调查'的属性!?!?它是如何消失的?
所以,我硬编码了_has_poll = False,然后mrjob愉快地继续其工作,在AWS EMR中运行我的工作,子进程使用communic_with_select ...而且我坚持使用手工修改的标准库...
有什么建议吗? : - )
答案 0 :(得分:3)
我遇到了类似的问题,结果是gevent用select
取代了内置的gevent.select.select
模块,该模块没有poll
方法(因为它是一种阻塞方法) )。
但是出于某些原因,默认情况下,gevent不修补使用subprocess
的{{1}}。
一个简单的解决方法是将select.poll
替换为subprocess
:
gevent.subprocess
如果在导入mrjob库之前执行此操作,它应该可以正常工作。
答案 1 :(得分:1)
很抱歉写一个完整的答案而非评论,否则我会丢失代码缩进。
我无法直接帮助你,因为某些内容似乎与你的代码紧密相关,但我可以通过依赖Python模块可以成为任意对象的事实来帮助你找到答案,尝试这样的事情:
class FakeModule(dict):
def __init__(self, origmodule):
self._origmodule = origmodule
self.__all__ = dir(origmodule)
def __getattr__(self, attr):
return getattr(self._origmodule, attr)
def __delattr__(self, attr):
if attr == "poll":
raise RuntimeError, "Trying to delete poll!"
self._origmodule.__delattr__(attr)
def replaceSelect():
import sys
import select
fakeselect = FakeModule(select)
sys.modules["select"] = fakeselect
replaceSelect()
import select
del select.poll
你将获得如下输出:
Traceback (most recent call last):
File "domy.py", line 27, in <module>
del select.poll
File "domy.py", line 14, in __delattr__
raise RuntimeError, "Trying to delete poll!"
RuntimeError: Trying to delete poll!
通过在代码中调用replaceSelect(),你应该能够获得的追溯有人正在删除poll(),这样你就可以理解为什么了。
我希望我的FakeModule实现足够好,否则你可能需要修改它。