我如何在c#中使用async来获得我需要的结果,从一个称为进程的python脚本?



我已经使用c# .NET构建了一个GUI,我需要合并一个Python脚本,如果在面板上选择了一个复选框,当"PROCEED"按钮。python脚本应该在后台运行,然后我想在GUI启动的主进程结束时在消息框中打印字符串结果。重要的是,我只希望在选中复选框时弹出消息框。

我知道如何从c#调用Python,但我仍然有点模糊如何收集和显示使用异步函数的结果。根据微软文档,我知道我需要使用Task对象,但我不能完全按照我的意图实现它。以下是我到目前为止在代码中使用的文档供参考:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

这是我第一次在c#中使用异步。

下面是我的相关函数代码(为了清晰起见缩短了),然后我将用问题详细描述问题:

async private void proceedClicked()
{    
if (checkBox.Checked)
{
string cmd = ""; // some python command
Task<string> pythonTask = runProcAsync(cmd);
}
// do some other processing
if (checkBox.Checked)
{
var pythonResult = await pythonTask;
// print result to a message box
}
}
private Task runProcAsync(string cmd)
{
return Task.Run(() =>
{
callPython(cmd);
});
}

private string callPython(string cmd)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "python.exe";// full path to python
start.Arguments = cmd;
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
return result;
}
}
}

以下是我对实现方法的一些细节的问题:

  1. 我如何对齐任务和任务对象,使它们匹配?我尝试过使用Task,然后使用Task.Result()来获取字符串,但Result()不存在作为我声明的Task var的方法。然后我试着使用任务<>作为类型,但Task.Run()抱怨隐式转换,因为它不受支持,必须是显式的。(字符串应该在那些克拉我的第二种方法,但格式是阻止我和IDK如何修复它)。
  2. 如何声明任务对象所以它出现在两个条件范围?我尝试在外部作用域中用构造函数声明它,但是没有对象的构造函数。我可以在没有构造函数的情况下在外部作用域中声明变量,但随后在第二个作用域中得到一个错误,即变量在第一个作用域中赋值后未赋值。我的直觉告诉我在外部作用域中声明它为none,在第一个条件块中赋值,然后在第二个条件块中检查非none的值。
  3. 是我使用async/await适当/正确,还是有更好的方法?既然我正在调用一个进程,这将如何影响async的使用?

事先感谢您的建议/帮助!

除了返回结果的问题外,您不应该在异步代码中使用阻塞函数。而是一直使用async:

async private void proceedClicked()
{    
if (checkBox.Checked)
{
string cmd = ""; // some python command
Task<string> pythonTask = runProcAsync(cmd);
}
// do some other processing
if (checkBox.Checked)
{
var pythonResult = await pythonTask;
// print result to a message box
}
}
private async Task<string> runProcAsync(string cmd)
{
ProcessStartInfo start = new ProcessStartInfo
{
FileName = "python.exe", // full path to python
Arguments = cmd,
UseShellExecute = false,
RedirectStandardOutput = true,
};
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string result = await reader.ReadToEndAsync();
return result;
}
}
}
private Task runProcAsync(string cmd)
{
return Task.Run(() =>
{
callPython(cmd);
});
}

应该是:

private Task<string> runProcAsync(string cmd)
{
// you should be able to omit <string> here, as long as the return type is explicitly a string
return Task.Run<string>(() =>
{
return callPython(cmd);
});
}

请随意查看微软关于Task的一些文档,以及他们关于基于任务的异步编程的指南。

我注意到您还试图使用Task.Result就好像它是一个方法,而事实上它是Task类的一个属性。

最新更新