在无限循环中通过C#调用的Python不返回值 - c#

我当前正在实现一个.Net应用程序,该应用程序连接到Raspberry SenseHat。为此,我正在使用Python实现https://pythonhosted.org/sense-hat/并通过Processes调用python脚本,以使其尽可能松散地耦合。
一切正常,但操纵杆存在一些问题:该示例在Python脚本中使用了无限循环。我的“ Joystock.py”脚本当前看起来像这样:

import sys
try:
   import queue
except ImportError:
   import Queue as queue
import threading
import requests

from sense_hat import SenseHat
sense = SenseHat()

# Taken from https://stackoverflow.com/questions/48429653/python-returning-values-from-infinite-loop-thread
def _listen(queue):
  while True:
    event = sense.stick.wait_for_event(emptybuffer=True)
    val = event.action + ":" + event.direction
    queue.put(val)

def listen(params):
  q = queue.Queue()
  t1 = threading.Thread(target=_listen, name=_listen, args=(q,))
  t1.start()

  while True:
    value = q.get()
    print(value)

if __name__ == '__main__':
  args = sys.argv
  args.pop(0) # Remove file path
  methodName = args.pop(0) # Pop method name

  globals()[methodName](args)

底部是通过参数传递我想调用的方法名称和参数。
我的C#调用看起来像这样:

public void Listen(PythonListeningRequest request)
{
    var startInfo = _startInfoFactory.CreateForListening(request);

    var process = Process.Start(startInfo);
    process.BeginErrorReadLine();
    process.BeginOutputReadLine();
    process.EnableRaisingEvents = true;
    process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
    {
        Console.WriteLine("Input: " + e.Data);
    };

    process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
    {
        Console.WriteLine("Error: " + e.Data);
    };
}

以及ProcessStartInfo的定义:

public ProcessStartInfo CreateForListening(PythonRequest request)
{
    return new ProcessStartInfo
    {
        FileName = FindPythonExeFilePath(),
        Arguments = CreateArgumentsString(request),
        UseShellExecute = false,
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        CreateNoWindow = true,
        WindowStyle = ProcessWindowStyle.Hidden
    };
}

private static string CreateArgumentsString(PythonRequest request)
{
    var sb = new StringBuilder();
    sb.Append(request.FilePath);
    sb.Append(" ");

    sb.Append(request.MethodName);
    sb.Append(" ");

    foreach (var arg in request.Arguments)
    {
        sb.Append(arg.AsString());
        sb.Append(" ");
    }

    var result = sb.ToString();
    return result;
}

private string FindPythonExeFilePath()
{
    var possibleFilePaths = new string[]
    {
        @"C:\Users\mlm\AppData\Local\Programs\Python\Python37-32\python.exe",
        @"C:\WINDOWS\py.exe",
        "/usr/bin/python"
    };

    var existingPythonPath = possibleFilePaths.FirstOrDefault(fp => _fileSystem.File.Exists(fp));
    Guard.That(() => existingPythonPath != null, "No python path found.");

    return existingPythonPath;
}

正如您在python部分中看到的那样,这里使用了一个队列,这是我从另一个SO问题获得的。不幸的是,它仍然不起作用,一旦代码中包含“ t1.start()”,我就永远不会得到返回值。

手动尝试python脚本可以正常工作,所以我想问题是与C#的进程连接吗?不幸的是,我没有发现与此行为相关的任何东西,因此有人知道什么,可能导致此问题吗?

参考方案

底线:在任一流上均使用sys.stdoutsys.stderr后跟flush(),并避免使用print

由于我无法使用SenseHat,因此将您的示例缩小为:

try:
    import queue
except ImportError:
    import Queue as queue
import threading
import time
import sys

# Taken from https://stackoverflow.com/questions/48429653/python-returning-values-from-infinite-loop-thread
def _listen(queue):
    val =0
    while True:
        time.sleep(1)
        val = val+1
        queue.put(val)


def listen(params):
    q = queue.Queue()
    t1 = threading.Thread(target=_listen, name=_listen, args=(q,))
    t1.start()

    while True:
        value = q.get()
        sys.stdout.write(str(value) + '\n')
        sys.stdout.flush()


if __name__ == '__main__':
    args = sys.argv
    args.pop(0)  # Remove file path
    methodName = args.pop(0)  # Pop method name

    globals()[methodName](args)

至于C#部分,我没有改变,只是摆脱了class PythonRequest

这似乎有效。而使用print(value)而不是sys.stdout.write(str(value) + '\n') sys.stdout.flush()我没有从回调OutputDataReceived获得任何返回值

因此,我相信您必须在sys.stdoutsys.stderr上进行编写,然后强制flush在通过管道传输到C#的流上进行编写。否则,使用print填充标准输出缓冲区,而不必刷新。

Python-crontab模块 - python

我正在尝试在Linux OS(CentOS 7)上使用Python-crontab模块我的配置文件如下:{ "ossConfigurationData": { "work1": [ { "cronInterval": "0 0 0 1 1 ?", "attribute&…

Python Pandas导出数据 - python

我正在使用python pandas处理一些数据。我已使用以下代码将数据导出到excel文件。writer = pd.ExcelWriter('Data.xlsx'); wrong_data.to_excel(writer,"Names which are wrong", index = False); writer.…

Python:在不更改段落顺序的情况下在文件的每个段落中反向单词? - python

我想通过反转text_in.txt文件中的单词来生成text_out.txt文件,如下所示:text_in.txt具有两段,如下所示:Hello world, I am Here. I am eighteen years old. text_out.txt应该是这样的:Here. am I world, Hello old. years eighteen a…

用大写字母拆分字符串,但忽略AAA Python Regex - python

我的正则表达式:vendor = "MyNameIsJoe. I'mWorkerInAAAinc." ven = re.split(r'(?<=[a-z])[A-Z]|[A-Z](?=[a-z])', vendor) 以大写字母分割字符串,例如:'我的名字是乔。 I'mWorkerInAAAinc”变成…

如何在python中将从PDF提取的文本格式化为json - python

我已经使用pyPDF2提取了一些文本格式的发票PDF。我想将此文本文件转换为仅包含重要关键字和令牌的json文件。输出应该是这样的:#PurchaseOrder {"doctype":"PO", "orderingcompany":"Demo Company", "su…