Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Multiprocess debugging support #57

Closed
karthiknadig opened this issue Feb 10, 2018 · 24 comments
Closed

Multiprocess debugging support #57

karthiknadig opened this issue Feb 10, 2018 · 24 comments
Assignees

Comments

@karthiknadig
Copy link
Member

pydev is currently started in single process mode. we need to pass --multiprocess flag as a command line arg. That may not be enough, we may need custom protocol messages to tell VS/VSC adapter that another process has started.

@karthiknadig
Copy link
Member Author

Currently just enabling --multiprocess causes this error:

Traceback (most recent call last):
  File "G:\pyenv\test1\lib\site-packages\_pydev_bundle\pydev_monkey.py", line 152, in patch_args
    from pydevd import SetupHolder
ImportError: cannot import name 'SetupHolder'

@DonJayamanne
Copy link
Contributor

DonJayamanne commented Feb 12, 2018

Does current version of PTVS support multi-process debugging?
I didn't think it did!

@int19h
Copy link
Contributor

int19h commented Feb 12, 2018

Nope. This is one of the new features that we'll get from pydevd.

@DonJayamanne
Copy link
Contributor

we may need custom protocol messages to tell VS/VSC adapter that another process has started.

I am certain this is available today.

@DonJayamanne
Copy link
Contributor

from pydevd import SetupHolder
ImportError: cannot import name 'SetupHolder'

I believe this is because pydevd is being imported from within PTVSD.

Also, check the following docs in the header of pydevd.py:

'''
Entry point module (keep at root):

This module starts the debugger.
'''

@huguesv
Copy link
Contributor

huguesv commented Apr 17, 2018

@fabioz
Copy link
Contributor

fabioz commented Jun 13, 2018

A note here: due to the way that things are wrapped I think ptvsd won't know how to talk to the newly created multiprocess, so, this won't be simple to add in the current structure.

The main issue is that ptvsd expects an in-memory pydevd and requires patching it in some places instead of launching pydevd and then acting as a server to it to just translate what's needed to vscode (in which case it could just treat the spawned process as a new pydevd process and translate the threads from that process accordingly to vscode -- i.e.: vscode doesn't need to know about new processes, the adapter could do the needed work to send messages to the right process given the thread ids).

Another thing is that the whole patching expects pydevd to be the main entry, not ptvsd (so, many other things would need to be patched for this to work).

I think the main issue it was done this way is because pydevd doesn't communicate through the debug adapter protocol, so, ideally pydevd itself could communicate through the debug protocol (instead of needing ptvsd as a wrapper) and then have ptvsd work more as a customization layer of pydevd and launching customization.

@DonJayamanne
Copy link
Contributor

I think the main issue it was done this way is because pydevd doesn't communicate through the debug adapter protocol,

Well, I think this is still possible. PTVSD talks to pydevd using the pydev protocol (over a fake socket). So, when dealing with multi-process debugging, all we need to do is, get PTVSD to talk to pydevd over an actual socket!

Isn't that all that's required? Or am I missing something?

/cc @karthiknadig @fabioz

@DonJayamanne
Copy link
Contributor

DonJayamanne commented Jul 17, 2018

Here's a proof of concept, managed to get this working very easily using existing code.

Here's the source for the prototype DonJayamanne@4f16466

multiproc

@DonJayamanne
Copy link
Contributor

@karthiknadig
We should be able to turn existing PTVSD code into a DA, by simply using a real socket instead of a fake socket when communicating with pydevd.
I.e. very simple minor changes to turn existing PTVSD into a DA.

That's pretty much what I did to get the above working, PTVSD is a DA in this case, and PyDevD is running in the child process.

/cc @ericsnowcurrently

@DonJayamanne DonJayamanne self-assigned this Jul 17, 2018
@fabioz
Copy link
Contributor

fabioz commented Jul 17, 2018

@DonJayamanne I think this would be the ideal solution -- I thought it'd be more work given the way customizations are done, but if you got it running with few changes, even better ;)

This would probably fix a number of other issues as pydevd could work standalone (so, issues such as regular exiting wouldn't be issues anymore and the debug adapter could do some things better without being in the same process -- one thing that comes to mind is not needing to redirect output unless it's a remote debug as the debug adapter could just grab the output from the subprocess pipe).

@DonJayamanne
Copy link
Contributor

This would probably fix a number of other issues as pydevd could work standalone

Agreed.

as the debug adapter could just grab the output from the subprocess pipe

Agreed. This would be lot more efficient as well.

@jwilges
Copy link

jwilges commented Aug 10, 2018

@DonJayamanne are these changes planned? Your approach sounds like it's a huge step forward. Do you have a patch to share? I'd be psyched to take a look at it and try it locally. My current workarounds for multi-process debugging are cumbersome.

@alphacentauri12
Copy link

Nice! 👍
A patch would be great for the moment! ;-)

@gandalfsaxe
Copy link

Will this issue also cover Python multiprocessing's Pool().map?

https://docs.python.org/3.4/library/multiprocessing.html

@DonJayamanne
Copy link
Contributor

@karthiknadig @int19h

I couldn't get it to work, probably some setup issue.
I didn't pass the variable, instead is just modified _local.py to include the --multiprocess flag.

Please try this extension.
Note: PTVSD is not included in the extension, hence you'll need to set the environment variable in launch.json to use PTVSD for launch scenarios.

        {
            "type": "python",
            "env": {
                "PYTHONPATH": "/Users/donjayamanne/Desktop/Development/vscode/ptvsd"
            }
....
        },

python-2018.10.0-alpha.vsix.zip

@DonJayamanne
Copy link
Contributor

@int19h Got this working guys, had to make some changes at my end.

@karthiknadig
Copy link
Member Author

The debugger in master supports spawn processes, not fork processes. The work item is not complete. To use with multiprocessing on windows, you have to set multiprocessing.set_start_method('spawn')

The work is being tracked here: #425
Sample usage: https://github.com/Microsoft/ptvsd/blob/master/pytests/func/test_multiproc.py

@DonJayamanne
Copy link
Contributor

@int19h @karthiknadig

  • Please install and use this extension for testing multi-process debugging.
  • Please rename the extension to .vsix
  • Install in VSC

python-2018.10.0-alpha.vsix.zip

@karthiknadig karthiknadig modified the milestones: Oct 2018.2, Nov 2018.1 Oct 24, 2018
@karthiknadig karthiknadig removed this from the Nov 2018.1 milestone Nov 5, 2018
@sourabhXIII
Copy link

@DonJayamanne
Thanks for the patch.
Can you please help me understand how to install it? What should I rename to .vsix?

@karthiknadig
Copy link
Member Author

@sourabhXIII If you have the latest released version of the extension, then in the launch json put "subProcess": true to enable this. There are some limitations to this feature. It currently supports spawn subprocesses and fork subprocesses are a work in progress (see #943 for tracking).

If you are using this on linux/mac with multiprocessing library you have to set multiprocessing.set_start_method('spawn') before using it. That setting is supported only on python 3.x, for 2.x you have to wait until #943 is done.

@zchrissirhcz
Copy link

zchrissirhcz commented May 19, 2019

@karthiknadig
Hi, I'm using python3.7 and just using the example code below:

A.py

#!/usr/bin/env python
#coding: utf-8

import multiprocessing
multiprocessing.set_start_method('spawn')

from multiprocessing import Process, Event

import B

if __name__ == '__main__':
    update_event = Event()
    client_proc = Process(
                args=(update_event,),
                name="client",
                target=B.TestFunc,
            )
    client_proc.start()

    import time
    time.sleep(100)

B.py

#!/usr/bin/env python
#coding: utf-8
import time

def TestFunc(a):
    while True:
        time.sleep(5)
        print(a)

launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: cur file",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "subProcess": true
        }
    ]
}

When setting a break point in A.py's 12-th line, and by clicking step over in python debug mode, my VSCode just crash, failed to debug this very-simple-python-multiprocessing-code. Its output is:

chris@1080 /home/chris/work/debug_vscode                                                                                                  
⚡ cd /home/chris/work/debug_vscode ; env PYTHONIOENCODING=UTF-8 PYTHONUNBUFFERED=1 /home/chris/soft/miniconda3/bin/python /home/chris/.vscode/extensions/ms-python.python-2019.4.12954/pythonFiles/ptvsd_launcher.py --default --client --host localhost --port 46644 /home/chris/work/debug_vscode/A.py 
Traceback (most recent call last):
  File "/home/chris/.vscode/extensions/ms-python.python-2019.4.12954/pythonFiles/lib/python/ptvsd/__main__.py", line 424, in <module>
    main(sys.argv)
  File "/home/chris/.vscode/extensions/ms-python.python-2019.4.12954/pythonFiles/lib/python/ptvsd/__main__.py", line 410, in main
    run()
  File "/home/chris/.vscode/extensions/ms-python.python-2019.4.12954/pythonFiles/lib/python/ptvsd/__main__.py", line 327, in run_code
    eval(code, {})
  File "<string>", line 1, in <module>
  File "/home/chris/soft/miniconda3/lib/python3.7/multiprocessing/spawn.py", line 105, in spawn_main
    exitcode = _main(fd)
  File "/home/chris/soft/miniconda3/lib/python3.7/multiprocessing/spawn.py", line 114, in _main
    prepare(preparation_data)
  File "/home/chris/soft/miniconda3/lib/python3.7/multiprocessing/spawn.py", line 225, in prepare
    _fixup_main_from_path(data['init_main_from_path'])
  File "/home/chris/soft/miniconda3/lib/python3.7/multiprocessing/spawn.py", line 277, in _fixup_main_from_path
    run_name="__mp_main__")
  File "/home/chris/soft/miniconda3/lib/python3.7/runpy.py", line 263, in run_path
    pkg_name=pkg_name, script_name=fname)
  File "/home/chris/soft/miniconda3/lib/python3.7/runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "/home/chris/soft/miniconda3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/chris/work/debug_vscode/A.py", line 5, in <module>
    multiprocessing.set_start_method('spawn')
  File "/home/chris/soft/miniconda3/lib/python3.7/multiprocessing/context.py", line 242, in set_start_method
    raise RuntimeError('context has already been set')
RuntimeError: context has already been set
[1]    17598 terminated  env PYTHONIOENCODING=UTF-8 PYTHONUNBUFFERED=1   --default --client --host    
/home/chris/soft/miniconda3/lib/python3.7/multiprocessing/semaphore_tracker.py:144: UserWarning: semaphore_tracker: There appear to be 5 leaked semaphores to clean up at shutdown
  len(cache))
(base) 

So sad. It is still not usable for such a simple multiprocessing code?

My VSCode is just updated this afternoon, ubuntu16.04. Its detail:

版本 1.34.0
提交 a622c65b2c713c890fcf4fbf07cf34049d5fe758
日期 2019-05-15T21:55:35.507Z
Shell 3.1.8
渲染器 66.0.3359.181
Node 10.2.0
架构 6.6.346.32

@int19h
Copy link
Contributor

int19h commented May 19, 2019

This is not a debugger issue - the same behavior can be observed running A.py directly.

The reason is that this line:

multiprocessing.set_start_method('spawn')

must be inside the if __name__ ... block. Otherwise, it gets run twice in the child process, causing this exception.

@zchrissirhcz
Copy link

@int19h Thanks for your reply. It works for my pasted A.py and B.py example. Actually I was trying debugging a large python program and I'll try if it also works when it is available.

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

No branches or pull requests