进程间通信—命名管道

业务上,C++编写的进程A和GO编写的进程B,需要在同一设备内通信。为此测试不同通信方式的性能。

1. 创建命名管道

这里创建了4个,1个用于单线程测试中,另外3个用于多线程测试中。

管道数和线程数最好相等,否则需要使用锁,影响性能。

mkfifo mypipe
mkfifo mypipe0
mkfifo mypipe1
mkfifo mypipe2

2. C++程序写数据 (cpipe.cpp)

每次测试发送100w条32字节的数据。可以指定发送数据的线程数,最大是3

#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <vector>

#define SEND_TIMES 1000000
#define SEND_DATA "01234567890123456789012345678901"

using namespace std;

void writeToPipe(int numThreads, int threadId, const std::string& pipeName) {
    std::ofstream pipe;
    pipe.open(pipeName.c_str(), std::ios::out);

    if(!pipe.is_open()) {
        std::cerr << "Error opening pipe " << pipeName << std::endl;
        return;
    }

    for(int i = 0; i < SEND_TIMES/numThreads; i++) {
        pipe << "Thread " << threadId << SEND_DATA << std::endl; //每次写32字节
    }

    pipe.close();
}

void singleThd() {
    writeToPipe(1, 0, "mypipe");
    return;
}

void multiThds(int numThreads)
{
    std::vector<std::thread> threads;

    // 创建多个线程并启动
    for(int i = 0; i < numThreads; i++) {
        std::string pipeName = "mypipe" + std::to_string(i); // 不同的管道名称
        threads.push_back(std::thread(writeToPipe, numThreads, i, pipeName));
    }

    // 等待所有线程执行完成
    for(auto& t : threads) {
        t.join();
    }

    return;
}


int main(int argc, char* argv[]) {
    if(argc != 2) {
        cerr << "Usage: " << argv[0] << " <numThreads>" << endl;
        return 1;
    }

    int numThreads = std::stoi(argv[1]);
    if (numThreads == 1) {
        singleThd();
        cout << "使用"<< "1" << "个线程向1个管道中发送:" <<SEND_TIMES << " 次,"<< sizeof(SEND_DATA)-1 << "字节数据。" << endl;
    } else {
        if (numThreads > 3) {
            cout << "numThreads cannot large than 3." << endl;
        }
        multiThds(numThreads);
        cout << "使用"<< numThreads<< "个线程向"<<numThreads<<"个管道中发送:" <<SEND_TIMES << " 次,"<< sizeof(SEND_DATA)-1 << "字节数据。" << endl;
    }

    return 0;
}

编译&运行

运行的第一个参数为发送数据使用的线程数

g++ cpipe.cpp -o cpipe
./cpipe 1

3. GO程序读数据 (gpipe.go)

不同的线程从不同的管道中读数据

package main

import (
	"fmt"
	"os"
	"sync"
	"time"
	"strconv"
)

func readFromPipe(wg *sync.WaitGroup, ch chan []byte, pipeName string) {
	defer wg.Done()

	file, err := os.Open(pipeName)
	if err != nil {
		fmt.Println("Error opening pipe:", err)
		return
	}
	defer file.Close()

	buf := make([]byte, 100)
	for {
		n, err := file.Read(buf)
		if err != nil {
			if err.Error() == "EOF" {
				break // 读取到EOF时退出循环
			}
			fmt.Println("Error reading from pipe:", err)
			return
		}
		data := make([]byte, n)
		copy(data, buf[:n])
		ch <- data
	}
}

func multiThreadRead(numThreads int) {
	var wg sync.WaitGroup
	ch := make(chan []byte)
	entryCount := 0
	t1 := time.Now().UnixNano()

	for i := 0; i < numThreads; i++ {
		pipeName := "mypipe" + strconv.Itoa(i) // 每个线程读取不同的管道
		wg.Add(1)
		go readFromPipe(&wg, ch, pipeName)
	}

	go func() {
		wg.Wait()
		close(ch)
	}()

	for data := range ch {
		_ = string(data)
		entryCount++
	}

	t2 := (time.Now().UnixNano() - t1) / 1000000
	fmt.Printf("数据条目数量:%d, 多线程(%d个线程)所用时长:%d毫秒\n", entryCount, numThreads, t2)
}

func singleThreadRead() {
	file, err := os.Open("mypipe")
	if err != nil {
		fmt.Println("Error opening pipe:", err)
		return
	}
	defer file.Close()

	buf := make([]byte, 100)
	entryCount := 0
	t1 := time.Now().UnixNano()

	for {
		n, err := file.Read(buf)
		if err != nil {
			if err.Error() == "EOF" {
				break // 读取到EOF时退出循环
			}
			fmt.Println("Error reading from pipe:", err)
			return
		}
		_ = string(buf[:n])
		entryCount++
	}

	t2 := (time.Now().UnixNano() - t1) / 1000000
	fmt.Printf("数据条目数量:%d, 单线程所用时长:%d毫秒\n", entryCount, t2)
}


func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: go run main.go <numThreads>")
		return
	}

	numThreads, err := strconv.Atoi(os.Args[1])
	if err != nil {
		fmt.Println("Invalid number of threads")
		return
	}

	if numThreads <= 1 {
		singleThreadRead()
	} else {
		multiThreadRead(numThreads)
	}
}

运行

使用1个线程读管道数据

go run gpipe.go 1

4. 实验结果

实验环境:Intel(R) Xeon(R) Gold 6161 CPU @ 2.20GHz

实验数据如下表,可以看到使用多管道、多线程可以提高数据读写性能,但非线性提升。

读(go)-写(c++) 线程数使用管道数读写数据量每次实验时长(ms)平均时长 (ms)
1-1132MB2856 
2924 
2837 
2757 
2883 
2826 
2795 
2774 
2705 
2739
2805.5
2-2232MB2195 
2130 
2035 
2080 
2174 
1981 
2309 
2242 
2075 
2115
2136.6
3-3332MB1754 
2128 
1887 
1960 
1966 
2076 
1956 
2043 
2098 
1892
1987.2

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值