如何处理C语言和Python之间的IPC通信?

9
我有一个包含两个进程的应用程序,一个是C语言编写的,另一个是Python编写的。C进程负责进行所有繁重的计算工作,而Python进程则处理用户界面。
C程序每秒向一个相当大的缓冲区写入4次数据,而Python进程读取这些数据。到目前为止,Python进程与C进程之间的通信是通过AMQP完成的。我想设置一些内存共享机制来减少开销并提高性能。
在这种情况下,我的选择是什么?理想情况下,我希望Python进程直接读取物理内存(最好是从内存而不是磁盘中读取),然后使用信号量或类似的机制处理竞争条件。然而,这是我很少接触的领域,所以我需要任何可以得到的帮助。
顺便说一下,我正在使用Linux操作系统。

共享内存?本地套接字? - Some programmer dude
1
你可以尝试使用内存映射文件(mmap)。 - Bakuriu
1
除非你能证明(测量)IPC是瓶颈,否则假设更快的IPC除了增加复杂性之外什么都不会做,这样只是浪费时间。 - msw
@Bakuriu 是的,mmap 看起来确实是一个替代方案。我还发现了 sysv_ipc,你有使用过这个模块吗? - c00kiemonster
如果您有源代码,考虑只需为C代码编写Python包装器。 - Mad Physicist
3个回答

8

这个问题已经被问了很长时间。我相信提出问题的人已经有了答案,所以我写这篇答案是为了后来的人更好地理解。

/*C code*/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define GETEKYDIR ("/tmp")
#define PROJECTID  (2333)
#define SHMSIZE (1024)

void err_exit(char *buf) {
    fprintf(stderr, "%s\n", buf);
    exit(1);
}


    int
main(int argc, char **argv)
{

    key_t key = ftok(GETEKYDIR, PROJECTID);
    if ( key < 0 )
        err_exit("ftok error");

    int shmid;
    shmid = shmget(key, SHMSIZE, IPC_CREAT | IPC_EXCL | 0664);
    if ( shmid == -1 ) {
        if ( errno == EEXIST ) {
            printf("shared memeory already exist\n");
            shmid = shmget(key ,0, 0);
            printf("reference shmid = %d\n", shmid);
        } else {
            perror("errno");
            err_exit("shmget error");
        }
    }

    char *addr;

    /* Do not to specific the address to attach
     * and attach for read & write*/
    if ( (addr = shmat(shmid, 0, 0) ) == (void*)-1) {
        if (shmctl(shmid, IPC_RMID, NULL) == -1)
            err_exit("shmctl error");
        else {
            printf("Attach shared memory failed\n");
            printf("remove shared memory identifier successful\n");
        }

        err_exit("shmat error");
    }

    strcpy( addr, "Shared memory test\n" );

    printf("Enter to exit");
    getchar();

    if ( shmdt(addr) < 0) 
        err_exit("shmdt error");

    if (shmctl(shmid, IPC_RMID, NULL) == -1)
        err_exit("shmctl error");
    else {
        printf("Finally\n");
        printf("remove shared memory identifier successful\n");
    }

    return 0;
}

#python 

# Install sysv_ipc module firstly if you don't have this
import sysv_ipc as ipc

def main():
    path = "/tmp"
    key = ipc.ftok(path, 2333)
    shm = ipc.SharedMemory(key, 0, 0)

    #I found if we do not attach ourselves
    #it will attach as ReadOnly.
    shm.attach(0,0)  
    buf = shm.read(19)
    print(buf)
    shm.detach()
    pass

if __name__ == '__main__':
    main()

需要首先执行C程序,并且不要在Python代码执行之前停止它,这将创建共享内存段并向其中写入一些内容。然后Python代码附加到相同的内存段并从中读取数据。

完成所有操作后,请按回车键停止C程序并删除共享内存ID。

我们可以在此处查看有关Python的SharedMemory的更多信息:http://semanchuk.com/philip/sysv_ipc/#shared_memory


2
建议#1: 最简单的方法应该是使用TCP。您提到数据大小很大。除非您的数据太庞大,否则使用TCP应该没问题。确保在C和Python中为传输/接收数据创建单独的线程。
建议#2: Python支持对C的封装。一个流行的封装是ctypes - http://docs.python.org/2/library/ctypes.html 假设您熟悉通过共享内存在两个C程序之间进行IPC,您可以编写一个C包装器,用于从共享内存中读取数据的Python程序。
还要检查以下讨论,其中讨论了Python和C ++之间的IPC:Simple IPC between C++ and Python (cross platform)

我同意,网络解决方案会更简单。但正如你所指出的,你也会产生额外的开销。无论如何,我正在尝试使用#2,我认为这更具吸引力。在我的特定示例中,生产者和消费者之间只有1:1的关系,因此锁定等不应该成为任何问题。 - c00kiemonster

0

把举重代码用C编写成库,然后提供一个Python模块作为包装器,如何?这实际上是一个相当常见的方法,特别是它允许在Python中进行原型设计和分析,然后将性能关键部分移植到C中。

如果你真的有理由需要两个进程,Python中有一个XMLRPC包可以方便这样的IPC任务。无论如何,除非你真的能证明性能要求这样做,否则请使用现有框架而不是发明自己的IPC。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接