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

标签 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)运行时(btw,在我的本地环境中util.DEBUG设置为True),该应用程序可以正常运行,但是然后我无法进行热重装这对我很重要。

我已尝试根据这篇文章https://superuser.com/a/194537/276726重新设置cygwin,但这并不能解决任何问题。

我还尝试按照this post中的步骤创建一个特殊的变基文件,但这也无济于事。

该应用程序可从Windows命令行以开发模式运行,因此,这是我目前的临时修补程序,但我希望我的Cygwin设置能够再次正常运行。

谢谢您的帮助!

最佳答案

在Cygwin世界中,您遇到了一个非常普遍的问题。有很多提到(处理)URL的URL,但是我将列出遇到的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 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环境

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(numpy已成功安装为scipy依赖项),但是我不能(作为副作用,import numpy加载了一堆.dll),但是调用fork(通过subprocess.Popen)并没有失败。然后,我决定亲自处理这个问题,并创建一个加载一些.dll的小程序,然后分叉自身(同样通过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,而不是Python扩展模块,尝试通过[Python 3.Docs]: ctypes - A foreign function library for Python加载它。这应该没有什么区别,因为无论Python如何看待它(作为模块还是作为外部.dll),它仍然必须将其加载到进程中(相同的方式)
该方案是:


我加载了2个这样的.dll(实际上是相同的.dll以不同的名称复制,因此它们都有相同的Preferred Base Address),因此第一个.dll可能会加载到该地址,而下一个.dll将是装在另一个
然后,我分叉该过程,然后在子进程中,基于随机因素,切换.dll加载顺序
当第二个.dll将在首选库中加载时,它将与父进程不一致,从而产生错误

最初,所有内容都在我的cwd中,然后(为了更贴近您的问题),我创建了一个带有文件的Python包。请注意,我没有采取正确的方式(通过setup.py文件安装),而是手动复制了所有内容





[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详细信息(Dependency Walker):

Img0

为什么常规的变基(rebaseall)无法解决问题?


Cygwin软件包具有一个安装后脚本,该脚本在其.dll上调用重新设置
在标准库路径(/ lib,/ usr / lib,...)中重新搜索。可以根据/usr/share/doc/Cygwin/_autorebase.README进行调整:


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


由于包可能包含.dll,因此Python需要进行此类调整。
像pip这样的软件包没有安装后脚本(该脚本会重新调整其.dll的基数)
VEnv位于用户的主路径中,而不位于标准库路径中(因此,即使是rebaseall也会忽略它们)


请注意,所有基于rebase的.dll文件都存储在一个数据库中:/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被变基工具拾取,需要对它们进行公告。这可以通过两种方式完成:


在其中一个自定义位置中指定它们,因此在下一次完全重新配置时,它们将不再被忽略(只需添加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


手动调整.dll的基础


他们俩都为我工作,但我仅以第二种变体为例(因为它更简单)。该过程包括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目录直接启动)启动命令,而不是从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窗口(检查其“首选基础”,并将其与上一张图像进行比较):

Img1

以及重新设置数据库的“查询”(现在从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应用程序无法在cygwin上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54370263/

相关文章:

python - Django NameError [应用程序名称] 未定义

python - 无法使用 flask-sqlalchemy 创建自动递增主键

在 docker 上运行时 Python flask reloader "Errno 2 No such file or directory"错误

gcc - 如何构建/更新 Cygwin GCC?

cygwin 上的 bash 脚本 - 似乎卡在连续命令之间。

windows - 如何配置 Windows 终端以启动 Cygwin (mintty) bash?

加载 .pkl 文件后出现 Python 错误 "ValueError: Did not recognise loaded array layout"

python - 如何检测十进制列是否应转换为整数或 double ?

python - 如何使用 PyUSB 写入控制端点

python - 使用调试运行 flask 时启动线程