Передача большого количества данных из Python в C-программу - PullRequest
7 голосов
/ 10 февраля 2011

У меня есть сценарий Python и программа на C, и мне нужно передать большие объемы данных из сценария Python, которые многократно вызывают программу на C. Прямо сейчас я позволяю пользователю выбирать между передачей их с помощью файла ASCII или двоичного файла, но оба они довольно медленные и бесполезные (я имею в виду файлы, которые полезны, если вы хотите сохранить данные, но я удаляю эти файлы в конце скрипт).

os.system не работает, аргументов слишком много, поскольку программа на C тоже использует файлы для возврата данных в Python, но это намного меньше данных.

Интересно, что я могу использовать для быстрого обмена? Запись файлов на RAM-диск? Если так, как я могу это сделать?

Я слышал, что можно вызывать функции из DLL с использованием ctypes, но я не знаю, как скомпилировать мою программу как DLL (я использую wxdevc + в Windows 7 64). Или оберните его, но все еще не знаете, может ли оно работать и эффективно ли оно.

Данные являются вершинами трехмерной сетки.

Я запускаю скрипт Python внутри другой программы ( blender (с открытым исходным кодом) и вызывается много раз (обычно более 500 раз), потому что он находится внутри цикла. Скрипт отправляет информацию о вершинах ( 1 int index и 3 плавающих координаты) в программу, и программа должна вернуть много вершин (только int index, потому что я могу найти соответствующие вершины с помощью Python).

Так что это не интерактивно, это больше похоже на функцию (но она написана на C). Программа script + C (которая является дополнением к blender), которую я пишу, должна быть кроссплатформенной, потому что она будет распространяться.

Программа на самом деле написана на C, и из Python я могу узнать адрес в памяти структуры, которая содержит данные вершин. Если бы только я знал, как это сделать, лучше было бы передать в C-программу только адрес, а оттуда найти все остальные вершины (хранятся в списке).

Но, насколько мне известно, я не могу получить доступ к пространству памяти другой программы, и я не знаю, вызывает ли она программу с помощью каналов или что-то еще, инициализирует новый поток или выполняется внутри скрипта (то есть на самом деле работает под Blender потоком)

Вот источник и blender/source/blender/makesdna/DNA_meshdata_types.h должно быть определением структуры

Ответы [ 4 ]

8 голосов
/ 10 февраля 2011

Трубы - очевидный путь; если ваша c-программа принимает ввод от stdin, вы можете использовать Popen. Это не создает «нить», как вы говорите в своем редактировании; он создает совершенно новый процесс с отдельной памятью:

from subprocess import Popen, PIPE

input = "some input"
cproc = Popen("c_prog", stdin=PIPE, stdout=PIPE)
out, err = cproc.communicate(input)

Вот более подробный пример. Во-первых, простая программа на c, которая выдает stdin:

#include<stdio.h>
#include<stdlib.h>
#define BUFMAX 100

int main() {
    char buffer[BUFMAX + 1];
    char *bp = buffer;
    int c;
    FILE *in;
    while (EOF != (c = fgetc(stdin)) && (bp - buffer) < BUFMAX) {
        *bp++ = c;
    }
    *bp = 0;    // Null-terminate the string
    printf("%s", buffer);
}

Затем программа на Python, которая передает данные (в данном случае из argv) в вышеприведенное:

from subprocess import Popen, PIPE
from sys import argv

input = ' '.join(argv[1:])
if not input: input = "no arguments given"
cproc = Popen("./c_prog", stdin=PIPE, stdout=PIPE)
out, err = cproc.communicate(input)
print "output:", out
print "errors:", err

Если вы не планируете использовать программу c без внешнего интерфейса Python, возможно, вам лучше встроить функцию c, возможно, используя instant.

from instant import inline
c_code = """
    [ ... some c code ... ] //see the below page for a more complete example.
"""
c_func = inline(c_code)

Как указывает Джо, вы также можете написать модуль на Python для c: Расширение Python с помощью C или C ++

В этом ответе обсуждаются другие способы объединения c и python: Как мне соединить Python и C-программу?

РЕДАКТИРОВАТЬ: Исходя из ваших правок, похоже, что вы действительно должны создать расширение cpython. Если вам нужен пример кода, дайте мне знать; но полное объяснение сделало бы неоправданно длинный ответ. Смотрите ссылку выше (Расширение Python ...) для всего, что вам нужно знать.

4 голосов
/ 10 февраля 2011

Если ваша операционная система поддерживает это, именованные каналы являются заменой файлов.

1 голос
/ 11 июня 2017

Я никогда не был удовлетворен ответами на связывание Python и C, поэтому я написал ответ после долгих исследований и размышлений.

test.c

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fp;
    char path[1035];

    fp = popen("python3 output2.py", "r");  // Open the command for reading.
    if (fp == NULL) {
        printf("Failed to run command\n" );
        exit(1);
    }

    while (fgets(path, sizeof(path), fp) != NULL)
       printf("C received %s", path);  // Read the output. 

    pclose(fp);  // close 

   return 0;
}

output2.py

import time
import os, sys

i = 0
while True :
    print("%d" %(i), flush=True)
    time.sleep(1)
    i = i + 1
1 голос
/ 10 февраля 2011

Вот идея, немного отличающаяся от других: напишите свою C-программу как модуль Python. Здесь - это вся информация, необходимая для этого.Затем вы можете передавать большие буферы назад и вперед между вашим кодом Python и вашим C-кодом.

...