gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 07:15:45 25 4
gpt4 key购买 nike

我目前正在实现一个 .Net 应用程序,它连接到 Raspberry SenseHat。为此,我使用 Python 实现 https://pythonhosted.org/sense-hat/并通过进程调用 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# 部分,我没有做任何更改,只是删除了 PythonRequest 类

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

所以我相信你必须在 sys.stdoutsys.stderr 上写入,然后强制 flush 在通过管道传输到你的流上写入C#。否则,使用 print 会填充标准输出缓冲区,但不一定会刷新。

关于c# - 通过 C# 调用的 Python 在无限循环中不返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57980163/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com