设置为开发人员模式时,Flask应用程序无法在cygwin上运行

时间:2019-01-25 17:37:11

标签: python flask cygwin

尝试使用以下背景在后台运行我的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设置正常运行。

感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

Cygwin 世界中,您遇到了一个非常普遍的问题。有很多 URL 提及(处理)它,但是我要列出遇到的内容:

  1. [SO]: Cygwin error: “-bash: fork: retry: Resource temporarily unavailable”
  2. [SO]: Cygwin issue - unable to remap; same address as parent
  3. [SuperUser]: Cygwin fatal error unable to remap.. What does it mean?
  4. [WordPress]: Cygwin and Rails – unable to remap to same address as parent; died waiting for dll loading, errno 11
  5. [SO]: Cygwin error: “child_info_fork::abort: Loaded to different address:”

[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()可靠地工作非常困难。

为了重现该问题,我使用了:

  • 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无法构建它。
由于[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__);
}

注释

  • 场景有点不同,我有一个常规的(虚拟) .dll ,而不是一个 Python扩展模块,我尝试通过{{3 }}。这应该没有什么区别,因为无论 Python 如何看待它(作为模块,还是作为外部 .dll ),它仍然必须加载它< / strong>(以同样的方式)
  • 方案是:
    • 我加载了2个这样的 .dll (实际上,是相同的 .dll ),它们以不同的名称复制,所以它们都具有相同的名称首选基址),因此第一个 st .dll 可能会加载到该地址,而下一个 .dll 将被加载到另一个
    • 然后我 fork 进程,并在子进程中基于随机因素切换 .dll 加载顺序
    • 在首选位置加载2 nd .dll 时,与父进程会出现不一致,从而产生错误
  • 一开始,所有内容都在我的 cwd 中,然后(为了更贴近您的问题),我用文件创建了一个 Python 包。请注意,我没有采取正确的方法(通过 setup.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 详细信息([Python 3.Docs]: ctypes - A foreign function library for Python):

Dependency Walker

为什么常规的 rebase rebaseall )无法解决问题?

  • Cygwin 软件包具有安装后脚本,该脚本在其 .dll s
  • 上调用 rebase
  • rebase 标准库路径 / lib / usr / lib ,。 ..)。可以根据 /usr/share/doc/Cygwin/_autorebase.README 进行调整:

      

    包装可以确定此类动态对象的潜在位置   通过将文件(以软件包命名)放入    /var/lib/rebase/dynpath.d / 。如果安装了任何动态对象   用户,这些位置应该在 /var/lib/rebase/user.d / 中发布   (如果有,文件名应与用户名相同   该系统上有多个用户)

    由于可能包含 .dll s

  • 的软件包,

    Python 需要进行这样的调整 像

  • pip 这样的软件包具有安装后脚本(该脚本会重新构建其 .dll s)
  • VEnv 在用户的主路径中,而在标准库路径不是(因此,甚至 rebaseall 都将忽略它们)

请注意,所有重新基于基础的 .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
    
  • 执行变基

    • 所有 Cygwin 进程都必须关闭(包括服务:例如 sshd
    • 我从 dash.exe 启动了命令(直接从 Cygwin bin dir从 Win 启动) ,,而不是 Mintty (请注意提示)
    [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 ,并将其与上一张图像进行比较):

Img0

还有 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 )。