我想使用PyCharm的调试器在 Python方法中设置的断点处停止,该方法由C#通过Python.NET 调用。但是,即使代码已明确执行,也永远不会命中断点。
问题似乎是在C#中创建了调用Python方法的线程。我知道,对于调试器可见的线程,必须调用settrace
。我认为,每个线程调用一次应该可以解决问题,但事实并非如此。因为在第一次执行Python方法后调用settrace
后,该方法及其调用的任何方法的断点都会被击中。但是在控制权从该方法传递回C#之后,在同一线程上再次调用Python方法并没有达到断点。
这是Python的一面;想象一下在两个print
语句处设置的断点。
import sys
import thread
import threading
sys.path.append(r'C:\Program Files (x86)\JetBrains\PyCharm Community Edition 2018.2.4\helpers\pydev')
import pydevd
import clr
from System.Threading import Thread
from System import Action
sys.path.append(r'C:\Code\PythonNetLib\bin\Debug')
clr.AddReference('MyLib')
from MyLib import MyThread, MyThreadBase
def init_debugging():
pydevd.settrace(suspend=False)
# breakpoint here is hit
print 'debugging initialized in thread {0}, managed thread ID {1}'.format(thread.get_ident(), Thread.CurrentThread.ManagedThreadId)
def hello():
# pydevd.settrace(suspend=False)
# breakpoint here is not hit unless pydevd.settrace is called again
print 'Hello from thread {0}, managed thread ID {1}'.format(thread.get_ident(), Thread.CurrentThread.ManagedThreadId))
t = MyThread()
t.ExecuteAsync(Action(init_debugging))
t.ExecuteAsync(Action(hello))
t.ExecuteAsync(Action(t.Stop))
t.Join()
出于说明目的,这是上面引用的包含MyThread
类的C#库的简化版本:
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace MyLib
{
public class MyThread: MyThreadBase
{
private Thread _thread;
public MyThread()
{
_thread = new Thread(Execute);
_thread.Start();
}
public void Join()
{
_thread.Join();
}
}
public class MyThreadBase
{
private ConcurrentQueue<Action> _queue;
private bool _stopped;
public MyThreadBase()
{
_queue = new ConcurrentQueue<Action>();
}
public void Execute()
{
while (!_stopped)
{
if (_queue.TryDequeue(out Action action))
{
action();
}
else
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}
public void ExecuteAsync(Action action)
{
_queue.Enqueue(action);
}
public void Stop()
{
_stopped = true;
}
}
}
解决方法::我注意到,当我没有在C#中创建线程而是像这样使用Python线程时,碰到了我的断点:
t = MyThreadBase()
tPy = threading.Thread(target=lambda: t.Execute())
tPy.start()
t.ExecuteAsync(Action(init_debugging))
t.ExecuteAsync(Action(hello))
t.ExecuteAsync(Action(t.Stop))
tPy.join()
在某些情况下,这是一个选项,但我无法控制要使用的C#库中的所有线程创建。
问题:我该怎么做才能使C#线程永久地为Python调试器所知,以使调试器在控制权传递回C#之后不会看不到线程。反复调用settrace
似乎有点麻烦,特别是因为我不确定如何从C#中调用所有方法。
我正在使用Python 2.7和.NET Framework 4.6.1,以防万一。