0

问题

我正在尝试从我的 Swift 可执行文件中调用 Python 函数。

这工作得很好,直到参数变得太长并且我开始收到错误:

未捕获的异常NSInternalInconsistencyException
原因:'无法 posix_spawn:错误 7'

这本质上意味着我发送 python 代码进行处理的数据(我的论点)太长了。

最后的选择

最明显的解决方案是将数据写入文件并将脚本发送到包含数据的文件的路径。这带来了明显的性能限制。

一个可能更好的选择

这就是我需要帮助的地方:我认为可以缓冲这些数据,而不是将其全部发送到一个块中。

我已经尝试使用许多不同的关键字组合对此进行研究,并且过去一天一直在网上阅读许多文章,但没有人回答我的问题:是否可以缓冲数据以绕过ARG_MAX大约 260000 字节的内核限制使用Processes 和Pipes?

编码

因为它总是有助于查看我当前用于调用 Python 函数的代码,所以这就是我所拥有的:

@discardableResult
public static func shell(_ args: String...) -> String {

    let task = Process()
    task.launchPath = "/usr/bin/env"
    task.arguments = args
    let pipe = Pipe()
    task.standardOutput = pipe
    task.launch()
    task.waitUntilExit()

    // return task.terminationStatus
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output: String = String(data: data, encoding: String.Encoding.utf8)!

    return output
}   
//  public static func shell(_ args: String...) -> String {}

稍后:

//
//  Call classifier on data
//
let pyStcriptPath = "\(Bundle.main.bundlePath)/Classification/****Classify.py"

//
// The fonction I'm calling here, 'shell', is the one defined just above in my question
//
let pyResult = shell("python", pyStcriptPath, "\(featureVector)", "\(signalType)")
4

1 回答 1

1

您可以改为使用管道将大负载发送到脚本的标准输入。当然,假设只有一个参数导致您的问题(即,您仍然可以使用常规命令行参数继续发送的所有其他内容)。

例如:

func shell(stdin input: String, _ args: String...) -> String {
    let task = Process()
    task.launchPath = "/usr/bin/env"
    task.arguments = args

    let inPipe = Pipe()
    task.standardInput = inPipe
    inPipe.fileHandleForWriting.write(input.data(using: .utf8)!)
    inPipe.fileHandleForWriting.closeFile()

    let outPipe = Pipe()
    task.standardOutput = outPipe

    task.launch()
    task.waitUntilExit()

    let data = outPipe.fileHandleForReading.readDataToEndOfFile()
    let output = String(data: data, encoding: .utf8)!

    return output
}

快速测试:

func bigString() -> String {
    var str = ""
    for i in 0..<50_000 {
        str.append("\(i % 10)")
    }
    return str
}

let script = "/PATH/TO/SCRIPT/echo.py"
let input = bigString()
let result = shell(stdin: input, "python", script, "some arg")
print(result)

印刷:

ARG:ABC
标准输入:012345678901234567890123...

echo.py脚本只是:

import sys
print "ARG:", sys.argv[1]
print "STDIN:", sys.stdin.read()
于 2019-02-06T02:04:46.397 回答