c# - 在无限循环中通过 C# 调用的 Python 不返回值
问题描述
我目前正在实现一个连接到 Raspberry SenseHat 的 .Net 应用程序。为此,我使用 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.stdout
并sys.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
因此,我相信您必须在通过管道传输到 C# 的流上进行写入sys.stdout
,sys.stderr
然后强制写入。flush
否则 usingprint
填充标准输出缓冲区并且不一定刷新。
推荐阅读
- excel - 如何将“If and vlookup”组合成1个公式
- node.js - 使用 typescript 编译问题 node.js,类型不匹配。heartBeatIntervalId 是数字类型,但 clearInterval 需要节点超时类型
- react-native - 反应原生区间,无法正确处理
- php - 代码点火器 URL 更改
- javascript - 让相机在 Aframe 中的路径上设置动画以保持专注于主题
- extjs - 在 extjs 的网格上添加启用和禁用作为上下文菜单
- docker - Docker 守护进程已经运行但仍然得到:无法连接到 unix:///var/run/docker.sock 上的 Docker 守护进程。docker 守护进程是否正在运行?
- java - 如何在 jython 中使用 cPickle 阅读
- sql - 带通配符的 BIGQUERY CASE 语句
- javascript - Vuejs如何选择按钮的范围