如何在单独的线程中分解从Python.NET调用的Python代码?

时间:2018-09-25 15:11:42

标签: c# python multithreading pycharm python.net

我想使用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,以防万一。

0 个答案:

没有答案