尝试使用以下背景在后台运行我的python flask应用程序后,立即发生了此问题:
$python app.py &
此操作立即失败。之后,以后再尝试运行该应用程序(我之前所做的都没有问题),最终会出现此错误:
$ python app.py
Running on http://127.0.0.1:8050/
Debugger PIN: 962-843-370
* Serving Flask app "app" (lazy loading)
* Environment: development
* Debug mode: on
2 [main] python3.6m 37104 child_info_fork::abort: unable to remap _lbfgsb.cpython-36m-x86_64-cygwin.dll to same address as parent (0x48E0000) - try running rebaseall
Traceback (most recent call last):
File "app.py", line 644, in <module>
app.run_server(debug=util.DEBUG)
File "/cygdrive/c/Users/mkupfer/Desktop/my_documents/01_Visualizations/eurostat/venv/lib/python3.6/site-packages/dash/dash.py", line 1293, in run_server
**flask_run_options)
File "/cygdrive/c/Users/mkupfer/Desktop/my_documents/01_Visualizations/eurostat/venv/lib/python3.6/site-packages/flask/app.py", line 943, in run
run_simple(host, port, self, **options)
File "/cygdrive/c/Users/mkupfer/Desktop/my_documents/01_Visualizations/eurostat/venv/lib/python3.6/site-packages/werkzeug/serving.py", line 812, in run_simple
reloader_type)
File "/cygdrive/c/Users/mkupfer/Desktop/my_documents/01_Visualizations/eurostat/venv/lib/python3.6/site-packages/werkzeug/_reloader.py", line 275, in run_with_reloader
sys.exit(reloader.restart_with_reloader())
File "/cygdrive/c/Users/mkupfer/Desktop/my_documents/01_Visualizations/eurostat/venv/lib/python3.6/site-packages/werkzeug/_reloader.py", line 132, in restart_with_reloader
close_fds=False)
File "/usr/lib/python3.6/subprocess.py", line 267, in call
with Popen(*popenargs, **kwargs) as p:
File "/usr/lib/python3.6/subprocess.py", line 709, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.6/subprocess.py", line 1275, in _execute_child
restore_signals, start_new_session, preexec_fn)
BlockingIOError: [Errno 11] Resource temporarily unavailable
该错误似乎源于在开发人员模式下运行,因为当我使用app.run_server(debug=False)
运行时(顺便说一句,util.DEBUG
在我的本地环境中设置为True
),该应用可以正常运行,但是这样我就不会热装,这对我很重要。
我已尝试根据此帖子https://superuser.com/a/194537/276726重新设置cygwin,但这并不能解决任何问题。
我也尝试按照this post中的步骤创建一个特殊的变基文件,但这也无济于事。
该应用程序可从Windows命令行以开发模式运行,因此这是我目前的临时修复程序,但我希望再次使Cygwin设置正常运行。
感谢您的帮助!
答案 0 :(得分:2)
在 Cygwin 世界中,您遇到了一个非常普遍的问题。有很多 URL 提及(处理)它,但是我要列出遇到的内容:
[Cygwin]: Problems with process creation中很好地解释了“幕后魔术”(重点是我的):
fork
的语义要求分叉的子进程具有与父进程完全相同的地址空间布局。但是, Windows不提供对进程之间的地址空间的克隆的本机支持,并且某些功能会破坏可靠的fork
实现。尤其是三个问题:
- DLL基地址冲突。与* nix共享库使用“位置无关代码”不同,Windows共享库采用固定的基地址。每当两个DLL的硬连接地址范围发生冲突(这种情况经常发生)时,Windows加载程序就必须将其中一个“重置”为另一个地址。但是,它可能无法一致地解决冲突,并且可能每次都使不同的dll变基和/或将其移动到不同的地址。 Cygwin涉及动态打开的库时,通常可以补偿此影响,但是静态链接的dll之间的冲突(在编译时已知的依赖关系)在
cygwin1.dll
初始化之前已得到解决,之后无法修复。通常只能使用rebaseall
工具消除引起问题的基址冲突来解决此问题。- 地址空间布局随机化(ASLR)。从Vista开始,Windows实现ASLR,这意味着线程堆栈,堆,内存映射文件和静态链接的dll在每个进程中都位于不同(随机)位置。此行为会干扰正确的
fork
,并且如果无法移动的对象(进程堆或系统dll)最终位于错误的位置, Cygwin将无能为力(尽管它会重试几次自动)。
尝试在[Cygwin.FAQ]: 4.45. How do I fix fork() failures?中进行故障排除(重点仍然有效)。冒着发送错误答案的风险,我将其粘贴在这里:
不幸的是,Windows不使用在类似UNIX的操作系统中发现的进程创建的fork / exec模型,因此Cygwin难以实现可靠且正确的
fork()
,这可能导致诸如以下错误消息:
- 无法将 somedll 重新映射到与父级相同的地址
- 无法分配堆
- 死于等待dll加载
- 孩子-1-在初始化之前等待longjmp死亡
- STATUS_ACCESS_VIOLATION
- 资源暂时不可用
上述错误的可能解决方案:
- 重新启动任何尝试使用
fork()
的过程(失败)。有时Windows会设置比通常对fork()
更具敌意的过程环境。- 请确保您已经淘汰(而不只是禁用了)BLODA上的所有软件。
- 如果您的操作系统和CPU支持,请从32位Cygwin切换到64位Cygwin。地址空间越大,fork()失败的可能性就越小。
尝试将环境变量CYGWIN设置为“ detect_bloda”,这将启用一些额外的调试,这可能表明是什么其他软件引起了该问题。
有关更多信息,请参见this mail。
强制执行完整的重新配置:运行 rebase-trigger fullrebase ,退出所有Cygwin程序并运行Cygwin设置。
>默认情况下,Cygwin的安装程序会自动对新安装的文件执行增量重新配置。强制执行完整的基准调整会导致在进行基准调整之前清除基准映射。
有关更多详细信息,请参见 / usr / share / doc / rebase / README 和/usr/share/doc/Cygwin/_autorebase。README >。
请注意,安装新软件包或更新现有软件包会抵消重新设置的影响,并经常导致
fork()
失败再次出现。出于技术原因,请参阅《用户指南》的process creation部分,以使
fork()
可靠地工作非常困难。
为了重现该问题,我使用了:
我尝试重现您的确切行为(使用 _lbfgsb * .dll ),但是pip -v install scipy
无法构建它。
由于[SciPy]: Installing SciPy on Windows描述了一个非常复杂的过程,因此我无法保证最终我能够重现该问题,因此我尝试使用 numpy .dll s( numpy 已作为 scipy 依赖项成功安装),但我却无法(作为副作用,{{ 1}}加载了一堆 .dll s,但是调用 fork (通过import numpy
进行调用)没有失败。
然后我决定亲自处理这件事,并创建一个加载一些 .dll 的小程序,然后分叉自身(同样通过subprocess.Popen
),以完成问题尽可能重现。
dll.c :
subprocess.Popen
code.py :
#include <stdio.h>
#if defined(_WIN32)
# define DLL_EXPORT __declspec(dllexport)
#else
# define DLL_EXPORT
#endif
DLL_EXPORT int test() {
printf("[%s] (%d) - [%s]\n", __FILE__, __LINE__, __FUNCTION__);
}
注释:
#!/usr/bin/env python3 import sys import os import subprocess import time import select import random import ctypes DLLS = [os.path.join(os.path.dirname(__file__), "dll{:d}.dll".format(item)) for item in range(2)] def main(): random.seed(os.getpid()) random.shuffle(DLLS) if len(sys.argv) == 1: print("Python {:s} on {:s}\n".format(sys.version.replace("\n", ""), sys.platform)) print("Process 0x{:08X}".format(os.getpid())) for dll in DLLS: ctypes.cdll.LoadLibrary(dll) idx = 0 while sys.stdin not in select.select([sys.stdin], [], [], 1)[0]: p = subprocess.Popen([sys.executable] + sys.argv + [str(idx)]) #p.communicate() time.sleep(1) idx += 1 else: sleep_time = 3 print("Process 0x{:08X} (inner) will end in {:d} seconds".format(os.getpid(), sleep_time)) time.sleep(sleep_time) if __name__ == "__main__": main()
因此,该错误是可重现的。我还要在此添加 .dll 详细信息([Python 3.Docs]: ctypes - A foreign function library for Python):
rebase 在标准库路径( / lib , / usr / lib ,。 ..)。可以根据 /usr/share/doc/Cygwin/_autorebase.README 进行调整:
由于可能包含 .dll s包装可以确定此类动态对象的潜在位置 通过将文件(以软件包命名)放入 /var/lib/rebase/dynpath.d / 。如果安装了任何动态对象 用户,这些位置应该在 /var/lib/rebase/user.d / 中发布 (如果有,文件名应与用户名相同 该系统上有多个用户)
Python 需要进行这样的调整 像
请注意,所有重新基于基础的 .dll 都存储在 DB 中: /etc/rebase.db(。$ {ARCH})。
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054370263]> ~/sopr.sh *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages *** [prompt]> [prompt]> uname -a CYGWIN_NT-10.0-WOW cfati-5510-0 2.11.2(0.329/5/3) 2018-11-08 14:30 i686 Cygwin [prompt]> ls code.py dll.c scipy.txt [prompt]> # List the currently installed packages in the !!! VEENV !!! Python [prompt]> ls -l ~/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages total 33 drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 __pycache__ -rw-r--r-- 1 cfati None 126 Jan 30 01:40 easy_install.py drwxr-xr-x+ 1 cfati None 0 Feb 2 21:41 numpy drwxr-xr-x+ 1 cfati None 0 Feb 2 21:41 numpy-1.16.1.dist-info drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 pip drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 pip-19.0.1.dist-info drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 pkg_resources drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 setuptools drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 setuptools-40.7.1.dist-info drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 wheel drwxr-xr-x+ 1 cfati None 0 Jan 30 01:40 wheel-0.32.3.dist-info [prompt]> [prompt]> ~/Work/Dev/VEnvs/py_032_03.06.04_test0/bin/python -m q054370263 /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/bin/python: No module named q054370263 [prompt]> # Create the package in site-packages dir [prompt]> mkdir ~/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263 [prompt]> cp code.py ~/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/__main__.py [prompt]> gcc -fPIC -shared -o ~/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/dll0.dll dll.c [prompt]> cp ~/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/dll0.dll ~/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/dll1.dll [prompt]> ls code.py dll.c scipy.txt [prompt]> ls -l ~/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263 total 260 -rwxr-x--- 1 cfati None 1012 Feb 3 12:39 __main__.py -rwxr-xr-x 1 cfati None 129844 Feb 3 12:22 dll0.dll -rwxr-xr-x 1 cfati None 129844 Feb 3 12:22 dll1.dll [prompt]> [prompt]> # Attempt to reproduce the problem by simply running the package [prompt]> ~/Work/Dev/VEnvs/py_032_03.06.04_test0/bin/python -m q054370263 Python 3.6.4 (default, Jan 7 2018, 17:45:56) [GCC 6.4.0] on cygwin Process 0x00001B38 18 [main] python3 21616 child_info_fork::abort: address space needed by 'dll0.dll' (0xD90000) is already occupied Traceback (most recent call last): File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "/usr/lib/python3.6/runpy.py", line 85, in _run_code exec(code, run_globals) File "/home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/__main__.py", line 37, in <module> main() File "/home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/__main__.py", line 25, in main p = subprocess.Popen([sys.executable] + sys.argv + [str(idx)]) File "/usr/lib/python3.6/subprocess.py", line 709, in __init__ restore_signals, start_new_session) File "/usr/lib/python3.6/subprocess.py", line 1275, in _execute_child restore_signals, start_new_session, preexec_fn) BlockingIOError: [Errno 11] Resource temporarily unavailable [prompt]> [prompt]> ~/Work/Dev/VEnvs/py_032_03.06.04_test0/bin/python -m q054370263 Python 3.6.4 (default, Jan 7 2018, 17:45:56) [GCC 6.4.0] on cygwin Process 0x000055E8 Process 0x00005764 (inner) will end in 3 seconds 1 [main] python3 21224 child_info_fork::abort: address space needed by 'dll1.dll' (0x6D0000) is already occupied Traceback (most recent call last): File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "/usr/lib/python3.6/runpy.py", line 85, in _run_code exec(code, run_globals) File "/home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/__main__.py", line 37, in <module> main() File "/home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/__main__.py", line 25, in main p = subprocess.Popen([sys.executable] + sys.argv + [str(idx)]) File "/usr/lib/python3.6/subprocess.py", line 709, in __init__ restore_signals, start_new_session) File "/usr/lib/python3.6/subprocess.py", line 1275, in _execute_child restore_signals, start_new_session, preexec_fn) BlockingIOError: [Errno 11] Resource temporarily unavailable
为了使 .dll 被 rebase 工具拾取,需要对它们进行广告。这可以通过两种方式完成:
在其中一个自定义位置中指定它们,因此在下一次完全重新配置时,它们将不再被忽略(只需添加 VEnv 目录以及其他(如果有的话)):
[prompt]> ls /var/lib/rebase/dynpath.d/ perl python2 python3 [prompt]> cat /var/lib/rebase/dynpath.d/python3 /usr/lib/python3.6/site-packages [prompt]> ls /var/lib/rebase/user.d/ [prompt]> [prompt]> grep -r "dll0.dll" /etc/rebase.db.i386 [prompt]>
手动重新构建 .dll s
他们两个都为我工作,但我仅以2 nd 变体为例(因为它更简单)。该过程包括2个步骤:
创建所有需要重新基础的 .dll 的列表
[prompt]> echo /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0 >/var/lib/rebase/user.d/${USER} [prompt]> cat /var/lib/rebase/user.d/cfati /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0
执行变基
[prompt]> find /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0 -name "*.dll" -o -name "*.so">/tmp/to_rebase.txt [prompt]> ls -l /tmp/to_rebase.txt -rw-r--r-- 1 cfati None 1773 Feb 3 13:05 /tmp/to_rebase.txt [prompt]> cat /tmp/to_rebase.txt /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_dummy.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_multiarray_module_test.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_multiarray_tests.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_multiarray_umath.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_operand_flag_tests.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_rational_tests.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_struct_ufunc_tests.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/core/_umath_tests.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/fft/fftpack_lite.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/linalg/lapack_lite.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/linalg/_umath_linalg.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/random/mtrand.cpython-36m-i386-cygwin.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/dll0.dll /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/dll1.dll
更新后的 Dependency Walker 窗口(检查其 Preferred Base ,并将其与上一张图像进行比较):
还有 rebase DB “查询”(现在从 Mintty 返回):
$ /bin/rebaseall -v -T /tmp/to_rebase.txt ... /usr/bin/cygargp-0.dll: new base = 6e7c0000, new size = 20000 /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/dll1.dll: new base = 6e7e0000, new size = 30000 /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/q054370263/dll0.dll: new base = 6e810000, new size = 30000 /home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0/lib/python3.6/site-packages/numpy/random/mtrand.cpython-36m-i386-cygwin.dll: new base = 6e840000, new size = 280000 ...
更重要的是,运行代码:
[prompt]> grep -r "dll0.dll" /etc/rebase.db.i386 Binary file /etc/rebase.db.i386 matches
可以看到它能够多次分叉(它只是停止了,因为我按下了 Enter )。