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

Break point fails with concurrent.futures.ProcessPoolExecutor in vscode python #1162

Closed
DonJayamanne opened this issue Feb 21, 2019 · 4 comments
Assignees
Milestone

Comments

@DonJayamanne
Copy link
Contributor

@machineCYC commented on Thu Feb 21 2019

Environment data

  • VS Code version: 1.31.1
  • OS and version: Ubuntu 18.04
  • Python version (& distribution if applicable, e.g. Anaconda): 3.6.5
  • Type of virtual environment used (N/A | venv | virtualenv | conda | ...): virtualenv
  • Relevant/affected Python packages and their versions: python inner packages

Expected behaviour

launch.json configuration as follows:

"configurations": [
   {
       "name": "Python",  
        "type": "python",  
        "request": "launch",  
        "program": "${file}",  
        "console": "integratedTerminal",  
        "cwd":"${workspaceFolder}/Code"  
  }]

test python code as follows:

import concurrent.futures

FIBS = [28, 10]
 
def fib(n):
    print(n)
    if n < 2:
        return 1
    return fib(n - 1) + fib(n - 2)
 
 
with concurrent.futures.ProcessPoolExecutor() as executor:
    executor.map(fib, FIBS)

Actual behaviour

Set break point in function fib. Must be stop.

But it does not.

Steps to reproduce:

1.Copy the provided configuration to launch.json
2.Copy the provided python code
3.Run debug mode in python code with launch.json

Logs

Output for Python in the Output panel (ViewOutput, change the drop-down the upper-right of the Output panel to Python)

$ cd /home/yenchen/Desktop/temp_test/Code ; env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1" /home/yenchen/basic_venv/bin/python3.6 /home/yenchen/.vscode/extensions/ms-python.python-2019.1.0/pythonFiles/ptvsd_launcher.py --default --client --host localhost --port 37647 /home/yenchen/Desktop/temp_test/Code/main.py

Output from Console under the Developer Tools panel (toggle Developer Tools on under Help; turn on source maps to make any tracebacks be useful by running Enable source map support for extension debugging)

Not anything.
@karthiknadig karthiknadig self-assigned this Feb 21, 2019
@karthiknadig karthiknadig added this to the Feb 2019.2 milestone Feb 21, 2019
@karthiknadig
Copy link
Member

@machineCYC This requires "subProcess": true in launch config to begin with.

It looks like it primarily depends on os.fork. This is not yet supported #943. so you have to switch multiprocessing to use spawn. Also, when using spawn, main module has to finish loading, so use this code to run:

import multiprocessing
multiprocessing.set_start_method('spawn', True)
import concurrent.futures

FIBS = [28, 10]

def fib(n):
    print(n)
    if n < 2:
        return 1
    return fib(n - 1) + fib(n - 2)


def main():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        executor.map(fib, FIBS)


if __name__ == '__main__':
    main()

That should get it to work:
image

@DonJayamanne One thing to note is that we need to pass pathmappings in this case even though it is launch. Since we attach to the child process.

        {
            "name": "Terminal",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "subProcess": true,
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "."
                }
            ],
        },

@karthiknadig
Copy link
Member

The above answer should resolve this issue.

@machineCYC
Copy link

@karthiknadig Thanks for this method, it can work. But have other methods without using
if name == 'main':
main()

just using
with concurrent.futures.ProcessPoolExecutor() as executor:
executor.map(fib, FIBS)

@int19h
Copy link
Contributor

int19h commented Mar 6, 2019

The key part for the workaround set_start_method - so long as you can somehow call that before any processes get spawned, it should work. If you have a single module, then doing that on top level, as in the code above, will suffice. If there are multiple modules, you can add a new module that just does set_start_method, and import it from the rest.

The __name__ == '__main___' bit is a general requirement for any module that has a function invoked via multiprocessing with the "spawn" implementation (which is the only one on Windows, so it's a requirement for portable code). But it's only needed if the module runs any code on top-level that you wouldn't want to also run in the child process when it starts:

https://docs.python.org/3/library/multiprocessing.html#the-spawn-and-forkserver-start-methods

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

4 participants