在Juypter中使用cython进行查询:ModuleNotFoundError:没有名为'_cython_magic的模块

时间:2018-08-18 19:44:47

标签: cython dask

我得到:

  

KilledWorker:(“('from_pandas-1445321946b8a22fc0ada720fb002544',4)”,'tcp://127.0.0.1:45940')

我已经阅读了关于后一个错误消息的explanation,但这与在堆栈跟踪顶部的错误消息一起都令人困惑:

  

distributed.utils-错误-工人已经存在tcp://127.0.0.1:35780

在笔记本上运行Jupyter notebook命令的终端上通过管道传输的实际错误:

  

ModuleNotFoundError:没有名为'_cython_magic_faba6120a194ab58ae9efd1da474433f'的模块

因此,既然我发现了本例的详细错误,我将自己研究如何解决此问题。有关此特殊配置的精确提示可能会很好,但是我想将所有cython代码提取到笔记本外部的python代码中会更明智,而不是让dask迷失对cython魔术命令的了解?

2 个答案:

答案 0 :(得分:1)

特定的cython错误确实看起来像是由于将编译配置为对工作者可见而引起的。当您执行%%cython时,将创建并构建一个临时扩展名,并最终将其导入到本地(客户端)会话中,而无需安装到python环境中。我不确定这到底是怎么发生的。

您至少应该确保在编译cython单元后创建客户端 ,然后它们可以继承所需的环境,但是很有可能猴子通过单元魔术来修补在任何情况下都太复杂了。

答案 1 :(得分:1)

这是一个完整的玩具示例(使用SLURM集群在JupyterLab上进行了测试)。 该示例使用Cython编译了一个琐碎的函数,该函数将两个整数相加,但是当然可以将相同的技术应用于复杂(且更有用)的代码。
这里的关键技巧是必须设置工人以查找和导入Cython库。
这需要导入pyximport,调用pyximport.install(),然后在每个Worker上导入Cython生成的模块。这是使用register_worker_callback()完成的。 请注意,Cython生成的模块位于<IPYTHONCACHEDIR/cython目录中(可以通过调用IPYTHONCACHEDIR找到IPython.paths.get_ipython_cache_dir())。必须将该目录添加到Python查找模块的路径,以便可以加载Cython生成的模块。
此示例假定SLURM,但这只是为了我的方便。 可以使用任何其他方法来设置dask.distributed“网络”(例如,参见http://distributed.dask.org/en/latest/setup.html)。

from dask import delayed

%load_ext cython

# Create a toy Cython function and put it into a module named remoteCython
%%cython -n remoteCython
def cython_sum(int a, int b):
    return a+b

# Set up a distributed cluster (minimal, just for illustration)
# I use SLURM.
from dask_jobqueue import SLURMCluster
from distributed import Client

cluster = SLURMCluster(memory="1GB",
                       processes=1,
                       cores=1,
                       walltime="00:10:00")

cluster.start_workers(1)   # Start as many workers as needed.



client = Client(cluster)

def init_pyx(dask_worker):
    import pyximport
    pyximport.install()

    import sys
    sys.path.insert(0,'<IPYTHONCACHEDIR>/cython/')   # <<< replace <IPYTHONCACHEDIR> as appropriate

    import remoteCython

client.register_worker_callbacks(init_pyx)  # This runs init_pyx() on any Worker at init

import remoteCython

# ASIDE: you can find where the full path of Cython-generated library by
# looking at remoteCython.__file__

# The following creates a task and submits to the scheduler.
# The task computes the sum of 123 and 321 via the Cython function defined above
future = client.compute(delayed(remoteCython.cython_sum)(123,321)) 

# The task is executed on the remote worker

# We fetch the result from the remote worker
print(future.result())   # This prints 444

# We're done. Let's release the SLURM jobs.
cluster.close()