Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

多进程报错 #50

Closed
kingmo888 opened this issue Jul 15, 2023 · 3 comments
Closed

多进程报错 #50

kingmo888 opened this issue Jul 15, 2023 · 3 comments

Comments

@kingmo888
Copy link

kingmo888 commented Jul 15, 2023

根据#21@myd7349提供的方法,可以解决不会N个进程弹出N个GUI了。
但是当子进程结束任务时,就会N个(pool数)下列错误,当确定后,主进程继续往下走。
image

多进程采用的进程池pool.apply_async的方式。

如果采用bat调用runtime\python.exe方式启动没有任何错误,采用pystand.exe方式启动就会有上述错误。

经过检查,子进程退出时将会跳转到muitlprocessing\spawn.py::spawn_main中执行sys.exit,从而引发截图Error。

========================
以下脚本将复现sys.exit(0)引起的Error:

import sys
import os


text = '''
import sys
sys.exit(0)
'''

PYSTAND_SCRIPT = '123.int'


def MessageBox(msg, info = 'Message'):
    import ctypes
    ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)
    return 0
os.MessageBox = MessageBox

#ifndef PYSTAND_CONSOLE
try:
    fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)
    fp = os.fdopen(fd, 'w')
    sys.stdout = fp
    sys.stderr = fp
except Exception:
    fp = open(os.devnull, 'w')
    sys.stdout = fp
    sys.stderr = fp



environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}
environ['__package__'] = None

#ifndef PYSTAND_CONSOLE
try:
    code = compile(text, PYSTAND_SCRIPT, 'exec')
    exec(code, environ)
except:
    import traceback, io
    sio = io.StringIO()
    traceback.print_exc(file = sio)
    os.MessageBox(sio.getvalue(), 'Error')

#else
code = compile(text, PYSTAND_SCRIPT, 'exec')
exec(code, environ)

查阅资料,sys.exit(0)会被捕捉,推荐使用os._exit(0),但在本例中就需要修改py自带的multiprocessing包了,不是太好。

@myd7349
Copy link
Contributor

myd7349 commented Jul 17, 2023

可以试试这个补丁:
myd7349@a845853

编译的版本在这里:
https://github.com/myd7349/PyStand/actions/runs/5575840236

try:
    code = compile(text, PYSTAND_SCRIPT, 'exec')
    exec(code, environ)
except:
    import traceback, io
    sio = io.StringIO()
    traceback.print_exc(file = sio)
    os.MessageBox(sio.getvalue(), 'Error')

这段代码本意是在 GUI 版本 AttachConsole 失败的情况下也能看到 Python 运行异常。但 try...except 同样会捕获到由:

sys.exit(0)

或:

raise SystemExit()

抛出的 SystemExit 异常。

重现该问题的 .int 脚本:

import os
import sys
os.MessageBox('Hello, world!')
sys.exit(0)

@myd7349
Copy link
Contributor

myd7349 commented Jul 17, 2023

又想了一下:

try:
    code = compile(text, PYSTAND_SCRIPT, 'exec')
    exec(code, environ)
except SystemExit:
    pass
except:
    import traceback, io
    sio = io.StringIO()
    traceback.print_exc(file = sio)
    os.MessageBox(sio.getvalue(), 'Error')

太麻烦了。

try:
    code = compile(text, PYSTAND_SCRIPT, 'exec')
    exec(code, environ)
except Exception:
    import traceback, io
    sio = io.StringIO()
    traceback.print_exc(file = sio)
    os.MessageBox(sio.getvalue(), 'Error')

即可。因为:

https://docs.python.org/3/library/exceptions.html

This exception is raised by the sys.exit() function. It inherits from BaseException instead of Exception so that it is not accidentally caught by code that catches Exception. This allows the exception to properly propagate up and cause the interpreter to exit. When it is not handled, the Python interpreter exits; no stack traceback is printed. The constructor accepts the same optional argument passed to sys.exit(). If the value is an integer, it specifies the system exit status (passed to C’s exit() function); if it is None, the exit status is zero; if it has another type (such as a string), the object’s value is printed and the exit status is one.

@myd7349 myd7349 mentioned this issue Jul 17, 2023
myd7349 added a commit to myd7349/PyStand that referenced this issue Jul 18, 2023
SystemExit inherits from BaseException instead of Exception.
@kingmo888
Copy link
Author

@myd7349 受教。谢谢。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants