设置为开发人员模式时,Flask 应用程序不再在 cygwin 中运行
Flask app no longer working from cygwin when set to developer mode
在后台尝试 运行 我的 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
错误似乎源于开发者模式下的 运行ning,因为当我 运行 和 app.run_server(debug=False)
时(顺便说一句,util.DEBUG
设置为 True
在我的本地环境中),该应用程序运行良好,但我没有得到对我很重要的热重新加载。
我已经尝试按照 post https://superuser.com/a/194537/276726 对 cygwin 进行变基,但这并没有解决任何问题。
我也尝试按照 this post 中的步骤创建一个特殊的 rebase 文件,但这也没有帮助。
该应用程序在我的 windows 命令行中以开发模式运行,因此这是我目前的临时修复,但我希望再次正确设置我的 Cygwin 运行ning。
感谢您的帮助!
您 运行 遇到了 Cygwin 世界中一个相当普遍的问题。有很多URL提到(处理)它,但我将列出我遇到的那些:
- [SO]: Cygwin error: “-bash: fork: retry: Resource temporarily unavailable”
- [SO]: Cygwin issue - unable to remap; same address as parent
- [SuperUser]: Cygwin fatal error unable to remap.. What does it mean?
- [WordPress]: Cygwin and Rails – unable to remap to same address as parent; died waiting for dll loading, errno 11
- [SO]:Cygwin 错误:“child_info_fork::abort:加载到不同的地址:”
“幕后魔法”在 [Cygwin]: Problems with process creation 中有很好的解释(重点 是我的):
The semantics of fork
require that a forked child process have exactly the same address space layout as its parent. However, Windows provides no native support for cloning address space between processes and several features actively undermine a reliable fork
implementation. Three issues are especially prevalent:
- DLL base address collisions. Unlike *nix shared libraries, which use "position-independent code", Windows shared libraries assume a fixed base address. Whenever the hard-wired address ranges of two DLLs collide (which occurs quite often), the Windows loader must "rebase" one of them to a different address. However, it may not resolve collisions consistently, and may rebase a different dll and/or move it to a different address every time. Cygwin can usually compensate for this effect when it involves libraries opened dynamically, but collisions among statically-linked dlls (dependencies known at compile time) are resolved before
cygwin1.dll
initializes and cannot be fixed afterward. This problem can only be solved by removing the base address conflicts which cause the problem, usually using the rebaseall
tool.
- Address space layout randomization (ASLR). Starting with Vista, Windows implements ASLR, which means that thread stacks, heap, memory-mapped files, and statically-linked dlls are placed at different (random) locations in each process. This behaviour interferes with a proper
fork
, and if an unmovable object (process heap or system dll) ends up at the wrong location, Cygwin can do nothing to compensate (though it will retry a few times automatically).
在 [Cygwin.FAQ]: 4.45. How do I fix fork() failures? 中尝试了故障排除程序(重点 仍然是我的)。冒着垃圾邮件的风险,我将把它粘贴在这里:
Unfortunately, Windows does not use the fork/exec model of process creation found in UNIX-like OSes, so it is difficult for Cygwin to implement a reliable and correct fork()
, which can lead to error messages such as:
- unable to remap somedll to same address as parent
- couldn't allocate heap
- died waiting for dll loading
- child -1 - died waiting for longjmp before initialization
- STATUS_ACCESS_VIOLATION
- resource temporarily unavailable
Potential solutions for the above errors:
Restart whatever process is trying (and failing) to use fork()
. Sometimes Windows sets up a process environment that is even more hostile to fork()
than usual.
Ensure that you have eliminated (not just disabled) all software on the BLODA.
Switch from 32-bit Cygwin to 64-bit Cygwin, if your OS and CPU support that. With the bigger address space fork() is less likely to fail.
Try setting the environment variable CYGWIN to "detect_bloda", which enables some extra debugging, which may indicate what other software is causing the problem.
See this mail for more information.
Force a full rebase: Run rebase-trigger fullrebase, exit all Cygwin programs and run Cygwin setup.
By default, Cygwin's setup program automatically performs an incremental rebase of newly installed files. Forcing a full rebase causes the rebase map to be cleared before doing the rebase.
See /usr/share/doc/rebase/README and /usr/share/doc/Cygwin/_autorebase.README for more details.
Please note that installing new packages or updating existing ones undoes the effects of rebase and often causes fork()
failures to reappear.
See the process creation section of the User's Guide for the technical reasons it is so difficult to make fork()
work reliably.
为了重现问题,我使用了:
- Cygwin 32:
- 运行进入问题的几率要高得多
- 不是我的主Cygwin env
- Python 3.6.4 + VEnv
- 位于/home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0
我尝试重现您的确切行为(使用 _lbfgsb*.dll),但 pip -v install scipy
无法构建它。
由于 [GitHub.SciPy]: Installing SciPy on Windows 描述了一个相当复杂的过程,我不能保证最后我能够重现问题,我尝试使用 numpy的.dlls(numpy已成功安装为scipy依赖项),但我无法做到(作为副作用,import numpy
加载了一堆 .dlls),但调用了 fork(通过subprocess.Popen)没有失败。
然后我决定自己动手,创建一个小程序加载一些 .dlls,然后 fork 自身(同样,通过 subprocess.Popen),使问题尽可能重现。
dll.c:
#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__);
}
code.py:
#!/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[=241,而不是 Python 扩展模块 =],我尝试通过 [Python.Docs]: ctypes - A foreign function library for Python 加载它。这应该没有什么区别,因为无论 Python 如何看待它(作为一个模块,或作为一个外部 .dll)它仍然需要加载它到进程中(同样的方式)
- 场景是:
- 我加载了2个这样的.dlls(其实是一样的.dll复制的在不同的名称下,因此它们都具有相同的 首选基址 ),因此 1st .dll 可能会加载到该地址,而下一个 .dll 将加载到另一个地址
- 然后我fork这个过程,在child中,我根据一个随机因素,切换.dll加载顺序
- 当2nd .dll加载到首选库时,会与[=390不一致=] 过程,产生错误
- 一开始一切都在我的cwd,然后(为了更接近你的问题),我创建了一个Python 与文件打包。请注意,我没有以正确的方式进行(通过 setup.py 文件安装),而是手动复制所有内容
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/Whosebug/q054370263]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in Whosebug (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 详细信息 (Dependency Walker):
为什么一个正规的rebase(rebaseall)不能解决问题?
Cygwin 软件包有一个 post 安装脚本,它调用 rebase [=108= .dlls
rebase 在标准库路径中搜索(/lib, /usr/lib, ...)。那个可以调整,根据/usr/share/doc/Cygwin/_autorebase.README:
Packages can make the potential locations of such dynamic objects
known by dropping a file (named after the package) in
/var/lib/rebase/dynpath.d/. If any dynamic objects are installed by
users, these locations should be advertised in /var/lib/rebase/user.d/
(the file name should be identical to the user name if there are
multiple users on this system)
Python 需要这样的调整,因为软件包可能包含 .dlls
pip 像包一样 not 有一个 post 安装脚本(这会改变他们的 .dlls)
VEnv在用户的主路径中,不是 在 标准库路径 中(因此,即使 rebaseall 也会忽略它们)
请注意,所有变基的 .dll 都存储在 DB 中:/etc/rebase.db(.${ARCH}).
[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 被 rebase 工具获取,它们需要被公布。这可以通过两种方式完成:
在其中一个自定义位置指定它们,这样在下一次完全变基时它们将不再被忽略(只需添加 te VEnv 目录,以及其他目录(如果有)):
[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
手动变基 .dlls
它们都对我有用,但我将仅以 2nd 变体为例(因为它更简单)。该过程包括 2 个步骤:
创建一个包含所有 .dll 需要变基的列表
[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
执行变基
- 必须关闭所有 Cygwin 进程(包括服务:例如 sshd)
- 我从dash.exe启动命令(直接从Win启动,从Cygwin bin dir), 而不是来自 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
...
更新后的 Dependency Walker window(检查其 Preferred Base,并将其与上一张图片中的进行比较):
还有 rebase DB“查询”(现在从 Mintty 返回):
[prompt]> grep -r "dll0.dll" /etc/rebase.db.i386
Binary file /etc/rebase.db.i386 matches
更重要的是,运行代码:
[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 0x000052D0
Process 0x00004634 (inner) will end in 3 seconds
Process 0x00004864 (inner) will end in 3 seconds
Process 0x00005CFC (inner) will end in 3 seconds
Process 0x00005A5C (inner) will end in 3 seconds
Process 0x00005098 (inner) will end in 3 seconds
Process 0x00005840 (inner) will end in 3 seconds
Process 0x000058C4 (inner) will end in 3 seconds
Process 0x000051DC (inner) will end in 3 seconds
Process 0x00001A5C (inner) will end in 3 seconds
Process 0x00003D2C (inner) will end in 3 seconds
Process 0x00000DA0 (inner) will end in 3 seconds
正如所见,它能够多次分叉(它只是因为我按下 Enter 才停止)。
在后台尝试 运行 我的 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
错误似乎源于开发者模式下的 运行ning,因为当我 运行 和 app.run_server(debug=False)
时(顺便说一句,util.DEBUG
设置为 True
在我的本地环境中),该应用程序运行良好,但我没有得到对我很重要的热重新加载。
我已经尝试按照 post https://superuser.com/a/194537/276726 对 cygwin 进行变基,但这并没有解决任何问题。
我也尝试按照 this post 中的步骤创建一个特殊的 rebase 文件,但这也没有帮助。
该应用程序在我的 windows 命令行中以开发模式运行,因此这是我目前的临时修复,但我希望再次正确设置我的 Cygwin 运行ning。
感谢您的帮助!
您 运行 遇到了 Cygwin 世界中一个相当普遍的问题。有很多URL提到(处理)它,但我将列出我遇到的那些:
- [SO]: Cygwin error: “-bash: fork: retry: Resource temporarily unavailable”
- [SO]: Cygwin issue - unable to remap; same address as parent
- [SuperUser]: Cygwin fatal error unable to remap.. What does it mean?
- [WordPress]: Cygwin and Rails – unable to remap to same address as parent; died waiting for dll loading, errno 11
- [SO]:Cygwin 错误:“child_info_fork::abort:加载到不同的地址:”
“幕后魔法”在 [Cygwin]: Problems with process creation 中有很好的解释(重点 是我的):
The semantics of
fork
require that a forked child process have exactly the same address space layout as its parent. However, Windows provides no native support for cloning address space between processes and several features actively undermine a reliablefork
implementation. Three issues are especially prevalent:
- DLL base address collisions. Unlike *nix shared libraries, which use "position-independent code", Windows shared libraries assume a fixed base address. Whenever the hard-wired address ranges of two DLLs collide (which occurs quite often), the Windows loader must "rebase" one of them to a different address. However, it may not resolve collisions consistently, and may rebase a different dll and/or move it to a different address every time. Cygwin can usually compensate for this effect when it involves libraries opened dynamically, but collisions among statically-linked dlls (dependencies known at compile time) are resolved before
cygwin1.dll
initializes and cannot be fixed afterward. This problem can only be solved by removing the base address conflicts which cause the problem, usually using therebaseall
tool.- Address space layout randomization (ASLR). Starting with Vista, Windows implements ASLR, which means that thread stacks, heap, memory-mapped files, and statically-linked dlls are placed at different (random) locations in each process. This behaviour interferes with a proper
fork
, and if an unmovable object (process heap or system dll) ends up at the wrong location, Cygwin can do nothing to compensate (though it will retry a few times automatically).
在 [Cygwin.FAQ]: 4.45. How do I fix fork() failures? 中尝试了故障排除程序(重点 仍然是我的)。冒着垃圾邮件的风险,我将把它粘贴在这里:
Unfortunately, Windows does not use the fork/exec model of process creation found in UNIX-like OSes, so it is difficult for Cygwin to implement a reliable and correct
fork()
, which can lead to error messages such as:
- unable to remap somedll to same address as parent
- couldn't allocate heap
- died waiting for dll loading
- child -1 - died waiting for longjmp before initialization
- STATUS_ACCESS_VIOLATION
- resource temporarily unavailable
Potential solutions for the above errors:
Restart whatever process is trying (and failing) to use
fork()
. Sometimes Windows sets up a process environment that is even more hostile tofork()
than usual.Ensure that you have eliminated (not just disabled) all software on the BLODA.
Switch from 32-bit Cygwin to 64-bit Cygwin, if your OS and CPU support that. With the bigger address space fork() is less likely to fail.
Try setting the environment variable CYGWIN to "detect_bloda", which enables some extra debugging, which may indicate what other software is causing the problem.
See this mail for more information.
Force a full rebase: Run rebase-trigger fullrebase, exit all Cygwin programs and run Cygwin setup.
By default, Cygwin's setup program automatically performs an incremental rebase of newly installed files. Forcing a full rebase causes the rebase map to be cleared before doing the rebase.
See /usr/share/doc/rebase/README and /usr/share/doc/Cygwin/_autorebase.README for more details.
Please note that installing new packages or updating existing ones undoes the effects of rebase and often causes
fork()
failures to reappear.See the process creation section of the User's Guide for the technical reasons it is so difficult to make
fork()
work reliably.
为了重现问题,我使用了:
- Cygwin 32:
- 运行进入问题的几率要高得多
- 不是我的主Cygwin env
- Python 3.6.4 + VEnv
- 位于/home/cfati/Work/Dev/VEnvs/py_032_03.06.04_test0
我尝试重现您的确切行为(使用 _lbfgsb*.dll),但 pip -v install scipy
无法构建它。
由于 [GitHub.SciPy]: Installing SciPy on Windows 描述了一个相当复杂的过程,我不能保证最后我能够重现问题,我尝试使用 numpy的.dlls(numpy已成功安装为scipy依赖项),但我无法做到(作为副作用,import numpy
加载了一堆 .dlls),但调用了 fork(通过subprocess.Popen)没有失败。
然后我决定自己动手,创建一个小程序加载一些 .dlls,然后 fork 自身(同样,通过 subprocess.Popen),使问题尽可能重现。
dll.c:
#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__);
}
code.py:
#!/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[=241,而不是 Python 扩展模块 =],我尝试通过 [Python.Docs]: ctypes - A foreign function library for Python 加载它。这应该没有什么区别,因为无论 Python 如何看待它(作为一个模块,或作为一个外部 .dll)它仍然需要加载它到进程中(同样的方式)
- 场景是:
- 我加载了2个这样的.dlls(其实是一样的.dll复制的在不同的名称下,因此它们都具有相同的 首选基址 ),因此 1st .dll 可能会加载到该地址,而下一个 .dll 将加载到另一个地址
- 然后我fork这个过程,在child中,我根据一个随机因素,切换.dll加载顺序
- 当2nd .dll加载到首选库时,会与[=390不一致=] 过程,产生错误
- 一开始一切都在我的cwd,然后(为了更接近你的问题),我创建了一个Python 与文件打包。请注意,我没有以正确的方式进行(通过 setup.py 文件安装),而是手动复制所有内容
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/Whosebug/q054370263]> ~/sopr.sh *** Set shorter prompt to better fit when pasted in Whosebug (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 详细信息 (Dependency Walker):
为什么一个正规的rebase(rebaseall)不能解决问题?
Cygwin 软件包有一个 post 安装脚本,它调用 rebase [=108= .dlls
rebase 在标准库路径中搜索(/lib, /usr/lib, ...)。那个可以调整,根据/usr/share/doc/Cygwin/_autorebase.README:
Packages can make the potential locations of such dynamic objects known by dropping a file (named after the package) in /var/lib/rebase/dynpath.d/. If any dynamic objects are installed by users, these locations should be advertised in /var/lib/rebase/user.d/ (the file name should be identical to the user name if there are multiple users on this system)
Python 需要这样的调整,因为软件包可能包含 .dlls
pip 像包一样 not 有一个 post 安装脚本(这会改变他们的 .dlls)
VEnv在用户的主路径中,不是 在 标准库路径 中(因此,即使 rebaseall 也会忽略它们)
请注意,所有变基的 .dll 都存储在 DB 中:/etc/rebase.db(.${ARCH}).
[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 被 rebase 工具获取,它们需要被公布。这可以通过两种方式完成:
在其中一个自定义位置指定它们,这样在下一次完全变基时它们将不再被忽略(只需添加 te VEnv 目录,以及其他目录(如果有)):
[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
手动变基 .dlls
它们都对我有用,但我将仅以 2nd 变体为例(因为它更简单)。该过程包括 2 个步骤:
创建一个包含所有 .dll 需要变基的列表
[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
执行变基
- 必须关闭所有 Cygwin 进程(包括服务:例如 sshd)
- 我从dash.exe启动命令(直接从Win启动,从Cygwin bin dir), 而不是来自 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 ...
更新后的 Dependency Walker window(检查其 Preferred Base,并将其与上一张图片中的进行比较):
还有 rebase DB“查询”(现在从 Mintty 返回):
[prompt]> grep -r "dll0.dll" /etc/rebase.db.i386 Binary file /etc/rebase.db.i386 matches
更重要的是,运行代码:
[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 0x000052D0 Process 0x00004634 (inner) will end in 3 seconds Process 0x00004864 (inner) will end in 3 seconds Process 0x00005CFC (inner) will end in 3 seconds Process 0x00005A5C (inner) will end in 3 seconds Process 0x00005098 (inner) will end in 3 seconds Process 0x00005840 (inner) will end in 3 seconds Process 0x000058C4 (inner) will end in 3 seconds Process 0x000051DC (inner) will end in 3 seconds Process 0x00001A5C (inner) will end in 3 seconds Process 0x00003D2C (inner) will end in 3 seconds Process 0x00000DA0 (inner) will end in 3 seconds
正如所见,它能够多次分叉(它只是因为我按下 Enter 才停止)。