【问题标题】:How can I handle IPC between C and Python?如何处理 C 和 Python 之间的 IPC?
【发布时间】:2013-04-13 18:38:30
【问题描述】:

我有一个包含两个进程的应用程序,一个在 C 中,一个在 Python 中。 C 进程是完成所有繁重工作的地方,而 Python 进程处理用户界面。

C 程序每秒向一个大缓冲区写入 4 次,而 Python 进程读取此数据。至此,与 Python 进程的通信已由 AMQP 完成。我宁愿在两个进程之间设置一些内存共享,以减少开销并提高性能。

我在这里有什么选择?理想情况下,我会简单地让 Python 进程直接读取物理内存(最好从内存而不是磁盘),然后使用信号量或类似的东西处理竞争条件。然而,这是我几乎没有经验的事情,所以如果能得到任何帮助,我将不胜感激。

顺便说一句,我正在使用 Linux。

【问题讨论】:

  • 共享内存?本地套接字?
  • 你可以试试内存映射文件(mmap)。
  • 在您能够证明(衡量)IPC 是瓶颈之前,您认为更快的 IPC 会做任何事情,但会增加复杂性,您就是在浪费时间。
  • @Bakuriu 是的 mmap 看起来不错。我还找到了sysv_ipc,对那个模块有什么经验吗?
  • 如果您有源代码,请考虑用 Python 为 C 代码编写一个包装器。

标签: python c ipc


【解决方案1】:

这个问题已经问了很久了。我相信提问者已经有了答案,所以我把这个答案写给后来的人。

/*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 中创建单独的线程以通过 TCP 传输/接收数据。

    建议 2: Python 支持 C 上的包装器。一种流行的包装器是 ctypes - http://docs.python.org/2/library/ctypes.html

    假设您熟悉两个 C 程序之间通过共享内存进行的 IPC,您可以为您的 python 程序编写一个 C-wrapper,从共享内存中读取数据。

    还请查看以下关于 python 和 C++ 之间 IPC 的讨论: Simple IPC between C++ and Python (cross platform)

    【讨论】:

    • 我同意,联网的解决方案会很简单。但正如您所指出的,您也会产生开销。无论如何,我正在尝试#2,我认为它更有吸引力。在我的特定示例中,生产者和消费者之间只有 1:1 的关系,因此锁定等不应该有任何问题。
    【解决方案3】:

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

    如果你真的有理由需要两个进程,那么 Python 中有一个 XMLRPC 包应该可以促进此类 IPC 任务。无论如何,请使用现有框架而不是发明自己的 IPC,除非您能真正证明性能需要它。

    【讨论】:

      猜你喜欢
      • 2015-06-07
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 2023-03-04
      • 1970-01-01
      • 2012-04-01
      相关资源
      最近更新 更多