从头开始摘树莓 - Day 3

安装 scipy

昨晚装 scipy,用 pip 装花了一个多小时,结果装完一 import scipy.fftpack,居然报不存在。

好吧,太娇气了,只能试别的操作了。

先吃后悔药:sudo pip uninstall numpy scipy

其实我们没必要用最新版本,所以先试试 apt-get,不行再从源代码编译呗。

sudo apt-get install libopenblas-base libatlas3-base
update-alternatives --list libblas.so.3
sudo apt-get install python-numpy python-scipy --reinstall

速度很快,就搞定了。但怎么检查有没有用上 BLAS 啥的呢?Stack Overflow 有网友说可以看动态库关联,他给的语句可能得改改,因为路径文件名啥的可能真的不一样,我折腾到最后用的是:

$ ldd /usr/lib/python2.7/dist-packages/numpy/core/multiarray.arm*
 linux-vdso.so.1 (0x7ea74000)
 /usr/lib/arm-linux-gnueabihf/libarmmem.so (0x76e32000)
 libblas.so.3 => /usr/lib/libblas.so.3 (0x76dca000)
 libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0x76d4b000)
 libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0x76d22000)
 libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0x76be3000)
 /lib/ld-linux-armhf.so.3 (0x76f99000)
 libopenblas.so.0 => /usr/lib/libopenblas.so.0 (0x76453000)
 libgfortran.so.3 => /usr/lib/arm-linux-gnueabihf/libgfortran.so.3 (0x7639e000)
 libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0x76371000)

所以算是有的了。再试试 import scipy.fftpack,也正常,那就完事了。

回过头来再跑程序,逐步解决了如下问题:

  1. 诶怎么 matplotlib 没了?那就再来:sudo apt-get install python-matplotlib
    (其实最早我试的 pip 安装 pip install -U matplotlib -i https://pypi.mirrors.ustc.edu.cn/simple,然后我就看到 pip 默默地又把我卸掉的 numpy 装回来了……于是它编译的时候我就迅速 Ctrl+C 了)
  2. 接着报没装 skimage,那就:sudo apt-get install python-skimage
  3. 继续 sudo pip install loky -i https://pypi.mirrors.ustc.edu.cn/simple

终于,能运行了。

设置自启动

差点忘记设置服务器自启动了。之前弄这个有好多坑,反正到最后翻了好多网上的做法,我的选择简单粗暴(先感谢 AskUbuntu ):

sudo nano /etc/rc.local

# 增加以下内容,注意 rc.local 运行的时候就是 root 权限的
exec 2> /tmp/rc.local.log # send stderr from rc.local to a log file
exec 1>&2 # send stdout to the same log file
set -x # tell sh to display commands before execution

python /home/pi/IPBroadcaster.py &
python /home/pi/cubik/server/server.py &
# echo `date +%Y-%b-%d_%H:%M:%S` > /tmp/ran_rc_local # check that rc.local ran
exit 0

回头解决代码问题

距离我还在埋头处理线程问题,已经经过了两天。终于我可以好好调试这个鬼问题了。

在这个项目里,线程安排是这个样子的:

  • 主进程运行过程中需要处理信号和 socket,而我们有一个运行时间很长的 taskInstance 线程,它按需开始结束,没有对主进程的环境依赖(准确来说,它有可能收到强退信号,但这个信号不能让主进程也强退了),需要有 Pipe 与主进程通信
  • taskInstance 线程运行过程中有一个 multiprocessing pool,同时运行几个 CPU 占用较多的 Python 任务(姑且叫做 visualSubtask 吧,反正里面东西不是我写的),输入输出需要能方便地传 Python 的数据类型,运行过程中最多就是 print 一些调试信息,倒不需要中途用 Pipe 传数据;同样,它有可能收到强退信号,但这个信号不能影响主进程强退

之前我是想试图解决信号的问题。实际上因为大部分的 forking 都是在加载完服务器程序之后进行的,所以对子进程发出的所有信号总会被服务器的信号处理代码截获,于是会导致主程序重启。

一种解决方案是在服务器程序加载之前做 prefork,把 taskInstance 的 process 先创建了。然而因为 taskInstance 是按需开始结束的,这样对它内部运行的改动还是挺大的(不过这部分代码是我写的,也不算麻烦,它也不会有长时间计算,轮询接收外头信号还是很容易,就是流程时序要求比较高)。更大的问题是,如果 taskInstance 意外停止了,之后要初始化它的那个“纯净”的环境就有点困难了。后面的路走不通的话,就还是得乖乖这么做了。

在逛 StackOverflow 的过程中看到有人推销自己写的 loky 库,似乎可以实现在程序运行中途 fork 一个纯净环境出来(Reusable executor)。两天前的中午我试了下,结果报错 Cannot pickle connection object. This object can only be passed when spawning a new process(传 Pipe 进子程序是我们程序必须要做的)。于是就得查查怎么把 connection object pass in before spawning a new process 咯。然而这库文档真的少得不行,只能仔细再研究看看了。

尝试许久,发现几个问题:

  1. 自己的 Pipe 传不进去。用事先在主线程定义好,子线程 global,得到的 Pipe 是坏的(查了下,说是升级到 Python 3+ 就好了,然而代码还有别人写的部分,懒得升级);说用 initializer 的 initargs 传进去,我硬是自己拿 loky 的 context 出来,把里面 Manager 的生成语句改了,加上自己的 initializer,再传给 get_reusable_executor 去用,结果啥都没收到,initializer 也没 print 东西出来。(感觉这个 Manager 程序根本没用到吧,放弃。)
  2. 会有 defunct 进程,感觉这个是 BUG。啥都没干只 get_reusable_executor 一次,结果 cherrypy 会根据代码更新自动重启,重启的时候  /usr/bin/python -c from loky.backend.semaphore_tracker import main; main(3) 这个进程似乎是没处理好,就 defunct 了,Ctrl+C 的时候倒是这些进程就消失了。

所以,还是得改成提前创建 taskInstance 的进程的方式,这时候我倒是觉得可以参考 http://www.defuze.org/archives/198-managing-your-process-with-the-cherrypy-bus.html 里 Broker 工作的方式重写下程序啦。

P.S. 送一条 OpenCV 3 + Python 3 的指令 cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D INSTALL_C_EXAMPLES=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules -D WITH_TBB=ON -D BUILD_TBB=ON -D WITH_OPENMP=ON -D BUILD_EXAMPLES=OFF -D WITH_NVCUVID=ON -D WITH_CUDA=ON -D BUILD_DOCS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_TESTS=OFF -D WITH_OPENCL=ON -D PYTHON_EXECUTABLE=$HOME/.virtualenvs/cv/bin/python3.5 -D PYTHON3_NUMPY_INCLUDE_DIRS=$HOME/.virtualenvs/cv/lib/python3.5/site-packages/numpy/core/include ..

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注