nvGRAPH API参考分析(二)

nvGRAPH Code Examples

本文提供了简单的示例。

1. nvGRAPH convert topology example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

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

size_t  n = 6, nnz = 10;

// nvgraph variables

nvgraphHandle_t handle;

nvgraphCSCTopology32I_t CSC_input;

nvgraphCSRTopology32I_t CSR_output;

float *src_weights_d, *dst_weights_d;

cudaDataType_t edge_dimT = CUDA_R_32F;

// Allocate source data

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

cudaMalloc( (void**)&(CSC_input->destination_offsets), (n+1)*sizeof(int));

cudaMalloc( (void**)&(CSC_input->source_indices), nnz*sizeof(int));

cudaMalloc( (void**)&src_weights_d, nnz*sizeof(float));

// Copy source data

float src_weights_h[] = {0.333333f, 0.5f, 0.333333f, 0.5f, 0.5f, 1.0f, 0.333333f, 0.5f, 0.5f, 0.5f};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

cudaMemcpy(CSC_input->destination_offsets, destination_offsets_h, (n+1)*sizeof(int), cudaMemcpyDefault);

cudaMemcpy(CSC_input->source_indices, source_indices_h, nnz*sizeof(int), cudaMemcpyDefault);

cudaMemcpy(src_weights_d, src_weights_h, nnz*sizeof(float), cudaMemcpyDefault);

// Allocate destination data

CSR_output = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSRTopology32I_st));

cudaMalloc( (void**)&(CSR_output->source_offsets), (n+1)*sizeof(int));

cudaMalloc( (void**)&(CSR_output->destination_indices), nnz*sizeof(int));

cudaMalloc( (void**)&dst_weights_d, nnz*sizeof(float));

// Starting nvgraph and convert

check(nvgraphCreate (&handle));

check(nvgraphConvertTopology(handle, NVGRAPH_CSC_32, CSC_input, src_weights_d,

&edge_dimT, NVGRAPH_CSR_32, CSR_output, dst_weights_d));

// Free memory

check(nvgraphDestroy(handle));

cudaFree(CSC_input->destination_offsets);

cudaFree(CSC_input->source_indices);

cudaFree(CSR_output->source_offsets);

cudaFree(CSR_output->destination_indices);

cudaFree(src_weights_d);

cudaFree(dst_weights_d);

free(CSC_input);

free(CSR_output);

return 0;

}

2. nvGRAPH convert graph example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

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

size_t  n = 6, nnz = 10, vert_sets = 2, edge_sets = 1;

// nvgraph variables

nvgraphHandle_t handle; nvgraphGraphDescr_t src_csc_graph;

nvgraphCSCTopology32I_t CSC_input;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// Allocate host data

float *pr_1 = (float*)malloc(n*sizeof(float));

void **vertex_dim = (void**)malloc(vert_sets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vert_sets*sizeof(cudaDataType_t));

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

// Initialize host data

float weights_h[] = {0.333333f, 0.5f, 0.333333f, 0.5f, 0.5f, 1.0f, 0.333333f, 0.5f, 0.5f, 0.5f};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

float bookmark_h[] = {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f};

vertex_dim[0] = (void*)bookmark_h; vertex_dim[1]= (void*)pr_1;

vertex_dimT[0] = CUDA_R_32F; vertex_dimT[1]= CUDA_R_32F, vertex_dimT[2]= CUDA_R_32F;

// Starting nvgraph

check(nvgraphCreate (&handle));

check(nvgraphCreateGraphDescr (handle, &src_csc_graph));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

CSC_input->destination_offsets = destination_offsets_h;

CSC_input->source_indices = source_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, src_csc_graph, (void*)CSC_input, NVGRAPH_CSC_32));

check(nvgraphAllocateVertexData(handle, src_csc_graph, vert_sets, vertex_dimT));

check(nvgraphAllocateEdgeData  (handle, src_csc_graph, edge_sets, &edge_dimT));

for (int i = 0; i < 2; ++i)

check(nvgraphSetVertexData(handle, src_csc_graph, vertex_dim[i], i));

check(nvgraphSetEdgeData(handle, src_csc_graph, (void*)weights_h, 0));

// Convert to CSR graph

nvgraphGraphDescr_t dst_csr_graph;

check(nvgraphCreateGraphDescr (handle, &dst_csr_graph));

check(nvgraphConvertGraph(handle, src_csc_graph, dst_csr_graph, NVGRAPH_CSR_32));

check(nvgraphDestroyGraphDescr(handle, src_csc_graph));

check(nvgraphDestroyGraphDescr(handle, dst_csr_graph));

check(nvgraphDestroy(handle));

free(pr_1); free(vertex_dim); free(vertex_dimT);

free(CSC_input);

return 0;

}

3. nvGRAPH pagerank example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

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

size_t  n = 6, nnz = 10, vert_sets = 2, edge_sets = 1;

float alpha1 = 0.9f; void *alpha1_p = (void *) &alpha1;

// nvgraph variables

nvgraphHandle_t handle; nvgraphGraphDescr_t graph;

nvgraphCSCTopology32I_t CSC_input;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// Allocate host data

float *pr_1 = (float*)malloc(n*sizeof(float));

void **vertex_dim = (void**)malloc(vert_sets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vert_sets*sizeof(cudaDataType_t));

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

// Initialize host data

float weights_h[] = {0.333333f, 0.5f, 0.333333f, 0.5f, 0.5f, 1.0f, 0.333333f, 0.5f, 0.5f, 0.5f};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

float bookmark_h[] = {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f};

vertex_dim[0] = (void*)bookmark_h; vertex_dim[1]= (void*)pr_1;

vertex_dimT[0] = CUDA_R_32F; vertex_dimT[1]= CUDA_R_32F, vertex_dimT[2]= CUDA_R_32F;

// Starting nvgraph

check(nvgraphCreate (&handle));

check(nvgraphCreateGraphDescr (handle, &graph));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

CSC_input->destination_offsets = destination_offsets_h;

CSC_input->source_indices = source_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, graph, (void*)CSC_input, NVGRAPH_CSC_32));

check(nvgraphAllocateVertexData(handle, graph, vert_sets, vertex_dimT));

check(nvgraphAllocateEdgeData  (handle, graph, edge_sets, &edge_dimT));

for (int i = 0; i < 2; ++i)

check(nvgraphSetVertexData(handle, graph, vertex_dim[i], i));

check(nvgraphSetEdgeData(handle, graph, (void*)weights_h, 0));

check(nvgraphPagerank(handle, graph, 0, alpha1_p, 0, 0, 1, 0.0f, 0));

// Get result

check(nvgraphGetVertexData(handle, graph, vertex_dim[1], 1));

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

free(pr_1); free(vertex_dim); free(vertex_dimT);

free(CSC_input);

return 0;

}

4. nvGRAPH SSSP example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

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

const size_t  n = 6, nnz = 10, vertex_numsets = 1, edge_numsets = 1;

float *sssp_1_h;

void** vertex_dim;

// nvgraph variables

nvgraphStatus_t status; nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSCTopology32I_t CSC_input;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// Init host data

sssp_1_h = (float*)malloc(n*sizeof(float));

vertex_dim  = (void**)malloc(vertex_numsets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vertex_numsets*sizeof(cudaDataType_t));

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

vertex_dim[0]= (void*)sssp_1_h; vertex_dimT[0] = CUDA_R_32F;

float weights_h[] = {0.333333, 0.5, 0.333333, 0.5, 0.5, 1.0, 0.333333, 0.5, 0.5, 0.5};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

check(nvgraphCreate(&handle));

check(nvgraphCreateGraphDescr (handle, &graph));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

CSC_input->destination_offsets = destination_offsets_h;

CSC_input->source_indices = source_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, graph, (void*)CSC_input, NVGRAPH_CSC_32));

check(nvgraphAllocateVertexData(handle, graph, vertex_numsets, vertex_dimT));

check(nvgraphAllocateEdgeData  (handle, graph, edge_numsets, &edge_dimT));

check(nvgraphSetEdgeData(handle, graph, (void*)weights_h, 0));

// Solve

int source_vert = 0;

check(nvgraphSssp(handle, graph, 0,  &source_vert, 0));

// Get and print result

check(nvgraphGetVertexData(handle, graph, (void*)sssp_1_h, 0));

//Clean

free(sssp_1_h); free(vertex_dim);

free(vertex_dimT); free(CSC_input);

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

return 0;

}

5. nvGRAPH Semi-Ring SPMV example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

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

size_t  n = 5, nnz = 10, vertex_numsets = 2, edge_numsets = 1;

float alpha = 1.0, beta = 0.0;

void *alpha_p = (void *)&alpha, *beta_p = (void *)&beta;

void** vertex_dim;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// nvgraph variables

nvgraphStatus_t status; nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSRTopology32I_t CSR_input;

// Init host data

vertex_dim  = (void**)malloc(vertex_numsets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vertex_numsets*sizeof(cudaDataType_t));

CSR_input = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSRTopology32I_st));

float x_h[] = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f};

float y_h[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f};

vertex_dim[0]= (void*)x_h; vertex_dim[1]= (void*)y_h;

vertex_dimT[0] = CUDA_R_32F; vertex_dimT[1]= CUDA_R_32F;

float weights_h[] = {1.0f, 4.0f, 2.0f, 3.0f, 5.0f, 7.0f, 8.0f, 9.0f, 6.0f, 1.5f};

int source_offsets_h[] = {0, 2, 4, 7, 9, 10};

int destination_indices_h[] = {0, 1, 1, 2, 0, 3, 4, 2, 4, 2};

check(nvgraphCreate(&handle));

check(nvgraphCreateGraphDescr(handle, &graph));

CSR_input->nvertices = n; CSR_input->nedges = nnz;

CSR_input->source_offsets = source_offsets_h;

CSR_input->destination_indices = destination_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, graph, (void*)CSR_input, NVGRAPH_CSR_32));

check(nvgraphAllocateVertexData(handle, graph, vertex_numsets, vertex_dimT));

for (int i = 0; i < vertex_numsets; ++i)

check(nvgraphSetVertexData(handle, graph, vertex_dim[i], i));

check(nvgraphAllocateEdgeData  (handle, graph, edge_numsets, &edge_dimT));

check(nvgraphSetEdgeData(handle, graph, (void*)weights_h, 0));

// Solve

check(nvgraphSrSpmv(handle, graph, 0, alpha_p, 0, beta_p, 1, NVGRAPH_PLUS_TIMES_SR));

//Get result

check(nvgraphGetVertexData(handle, graph, (void*)y_h, 1));

//Clean

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

free(vertex_dim); free(vertex_dimT); free(CSR_input);

return 0;

}

6. nvGRAPH Triangles Counting example

#include "stdlib.h"

#include "inttypes.h"

#include "stdio.h"

#include "nvgraph.h"

#define check( a ) \

{\

nvgraphStatus_t status = (a);\

if ( (status) != NVGRAPH_STATUS_SUCCESS) {\

printf("ERROR : %d in %s : %d\n", status, __FILE__ , __LINE__ );\

exit(0);\

}\

}

int main(int argc, char **argv)

{

// nvgraph variables

nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSRTopology32I_t CSR_input;

// Init host data

CSR_input = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSRTopology32I_st));

// Undirected graph:

// 0       2-------4

//  \     / \     / \

//   \   /   \   /   \

//    \ /     \ /     \

//     1-------3-------5

// 3 triangles

// CSR of lower triangular of adjacency matrix:

const size_t n = 6, nnz = 8;

int source_offsets[] = {0, 0, 1, 2, 4, 6, 8};

int destination_indices[] = {0, 1, 1, 2, 2, 3, 3, 4};

check(nvgraphCreate(&handle));

check(nvgraphCreateGraphDescr (handle, &graph));

CSR_input->nvertices = n;

CSR_input->nedges = nnz;

CSR_input->source_offsets = source_offsets;

CSR_input->destination_indices = destination_indices;

// Set graph connectivity

check(nvgraphSetGraphStructure(handle, graph, (void*)CSR_input, NVGRAPH_CSR_32));

uint64_t trcount = 0;

check(nvgraphTriangleCount(handle, graph, &trcount));

printf("Triangles count: %" PRIu64 "\n", trcount);

free(CSR_input);

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

return 0;

}

7. nvGRAPH Traversal example

void check_status(nvgraphStatus_t status){

if ((int)status != 0)    {

printf("ERROR : %d\n",status);

exit(0);

}

}

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

//Example of graph (CSR format)

const size_t  n = 7, nnz = 12, vertex_numsets = 2, edge_numset = 0;

int source_offsets_h[] = {0, 1, 3, 4, 6, 8, 10, 12};

int destination_indices_h[] = {5, 0, 2, 0, 4, 5, 2, 3, 3, 4, 1, 5};

//where to store results (distances from source) and where to store results (predecessors in search tree)

int bfs_distances_h[n], bfs_predecessors_h[n];

// nvgraph variables

nvgraphStatus_t status;

nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSRTopology32I_t CSR_input;

cudaDataType_t* vertex_dimT;

size_t distances_index = 0;

size_t predecessors_index = 1;

vertex_dimT = (cudaDataType_t*)malloc(vertex_numsets*sizeof(cudaDataType_t));

vertex_dimT[distances_index] = CUDA_R_32I;

vertex_dimT[predecessors_index] = CUDA_R_32I;

//Creating nvgraph objects

check_status(nvgraphCreate (&handle));

check_status(nvgraphCreateGraphDescr (handle, &graph));

// Set graph connectivity and properties (tranfers)

CSR_input = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

CSR_input->nvertices = n;

CSR_input->nedges = nnz;

CSR_input->source_offsets = source_offsets_h;

CSR_input->destination_indices = destination_indices_h;

check_status(nvgraphSetGraphStructure(handle, graph, (void*)CSR_input, NVGRAPH_CSR_32));

check_status(nvgraphAllocateVertexData(handle, graph, vertex_numsets, vertex_dimT));

int source_vert = 1;

//Setting the traversal parameters

nvgraphTraversalParameter_t traversal_param;

nvgraphTraversalParameterInit(&traversal_param);

nvgraphTraversalSetDistancesIndex(&traversal_param, distances_index);

nvgraphTraversalSetPredecessorsIndex(&traversal_param, predecessors_index);

nvgraphTraversalSetUndirectedFlag(&traversal_param, false);

//Computing traversal using BFS algorithm

check_status(nvgraphTraversal(handle, graph, NVGRAPH_TRAVERSAL_BFS, &source_vert, traversal_param));

// Get result

check_status(nvgraphGetVertexData(handle, graph, (void*)bfs_distances_h, distances_index));

check_status(nvgraphGetVertexData(handle, graph, (void*)bfs_predecessors_h, predecessors_index));

// expect bfs distances_h = (1 0 1 3 3 2 2147483647)

for (int i = 0; i<n; i++)  printf("Distance to vertex %d: %i\n",i, bfs_distances_h[i]); printf("\n");

// expect bfs predecessors = (1 -1 1 5 5 0 -1)

for (int i = 0; i<n; i++)  printf("Predecessor of vertex %d: %i\n",i, bfs_predecessors_h[i]); printf("\n");

free(vertex_dimT);

free(CSR_input);

check_status(nvgraphDestroyGraphDescr (handle, graph));

check_status(nvgraphDestroy (handle));

return 0;

}

nvGRAPH API参考分析(二)的更多相关文章

  1. nvGRAPH API参考分析(一)

    nvGRAPH API参考分析(一) 本文通过描述nvGRAPH库函数的输入/输出参数,数据类型和错误代码来指定其行为. 1.    返回值nvgraphStatus_t 除以下内容外,所有nvGRA ...

  2. PJSUA2开发文档--第十二章 PJSUA2 API 参考手册

    12 PJSUA2 API 参考手册 12.1 endpoint.hpp PJSUA2基本代理操作.  namespace pj PJSUA2 API在pj命名空间内. 12.1.1 class En ...

  3. Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI

    目录 引言 Search APIs Search API Search Request 可选参数 使用 SearchSourceBuilder 构建查询条件 指定排序 高亮请求 聚合请求 建议请求 R ...

  4. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  5. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  6. SQLite入门与分析(二)---设计与概念(续)

    SQLite入门与分析(二)---设计与概念(续)   写在前面:本节讨论事务,事务是DBMS最核心的技术之一.在计算机科学史上,有三位科学家因在数据库领域的成就而获ACM图灵奖,而其中之一Jim G ...

  7. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  8. 透过【百度地图API】分析双闭包问题

    原文:透过[百度地图API]分析双闭包问题 摘要: 有位API爱好者问到,昨天的教程里为什么不使用for循环?他使用for循环后,也发现代码无效.这是什么原因? ------------------- ...

  9. java微信开发API解析(二)-获取消息和回复消息

    java微信开发API解析(二)-获取消息和回复消息 说明 * 本演示样例依据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20 ...

随机推荐

  1. think php 5.x

    # Exploit Title: thinkphp 5.X RCE # Date: 2019-1-14 # Exploit Author: vr_system # Vendor Homepage: h ...

  2. C/C++ 手工实现IAT导入表注入劫持

    DLL注入有多种方式,今天介绍的这一种注入方式是通过修改导入表,增加一项导入DLL以及导入函数,我们知道当程序在被运行起来之前,其导入表中的导入DLL与导入函数会被递归读取加载到目标空间中,我们向导入 ...

  3. hdu4908 中位数子串

    题意:       给你N个数字组成的数列,然后问你这里面有多少个是以M为中位数的子序列. 思路:       首先分四中简单的情况求        (1) 就是只有他自己的那种情况 那么sum+1 ...

  4. LA3027简单带权并查集

    题意:       有n个点,一开始大家都是独立的点,然后给出一些关系,a,b表示a是b的父亲节点,距离是abs(a-b)%1000,然后有一些询问,每次询问一个节点a到父亲节点的距离是多少? 思路: ...

  5. [LeetCode每日一题]80. 删除有序数组中的重复项 II

    [LeetCode每日一题]80. 删除有序数组中的重复项 II 问题 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度. 不要使用额外 ...

  6. Junit单元测试&反射&注解

    内容索引 1. Junit单元测试 2. 反射 3. 注解 Junit单元测试: * 测试分类: 1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值. 2. 白盒测试:需要写代码的.关 ...

  7. 2-9-9-12分页机制(xp)

    10-10-12分页限制 10-10-12分页因为页表PEB只有四个字节所以只能访问2^32 = 4GB物理地址空间,现在的物理内存都大于4GB为了能访问到更多的物理内存2-9-9-12将PEB的大小 ...

  8. Java集合详解(三):HashMap原理解析

    概述 本文是基于jdk8_271版本进行分析的. HashMap是Map集合中使用最多的.底层是基于数组+链表实现的,jdk8开始底层是基于数组+链表/红黑树实现的.HashMap也会动态扩容,与Ar ...

  9. MSSQL·将一对多的数据合并为以指定分隔符的数据

    阅文时长 | 0.05分钟 字数统计 | 142.4字符 主要内容 | 1.引言&背景 2.Stuff函数语法&模拟场景 3.声明与参考资料 『MSSQL·将一对多的数据合并为以指定分 ...

  10. [Python] RPC实现

    单线程同步 使用socket传输数据 使用json序列化消息体 struct将消息编码为二进制字节串,进行网络传输 消息协议 1 // 输入 2 { 3 in: "ping", 4 ...