返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中PGPROC数据结构分析
  • 918
分享到

PostgreSQL中PGPROC数据结构分析

2024-04-02 19:04:59 918人浏览 泡泡鱼
摘要

本篇内容介绍了“postgresql中PGPROC数据结构分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成

本篇内容介绍了“postgresql中PGPROC数据结构分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、数据结构

宏定义


#define MAX_BACKENDS    0x3FFFF


typedef struct SHM_QUEUE
{
    struct SHM_QUEUE *prev;
    struct SHM_QUEUE *next;
} SHM_QUEUE;


#define INVALID_PGPROCNO        PG_INT32_MAX

LWLock
lwlock.c外的代码不应直接操作这个结构的内容,但我们必须声明该结构体以便将LWLocks合并到其他数据结构中。


typedef struct LWLock
{
    uint16      tranche;        
    //独占/非独占locker的状态
    pg_atomic_uint32 state;     
    //正在等待的PGPROCs链表
    proclist_head waiters;      
#ifdef LOCK_DEBUG//用于DEBUG
    //waiters的数量
    pg_atomic_uint32 nwaiters;  
    //的最后独占者
    struct PGPROC *owner;       
#endif
} LWLock;

PGPROC
每个后台进程在共享内存中都有一个PGPROC结构体.
全局上也存在未使用的PGPROC结构体链表,用于重用以便为新的后台进程进行分配.
该数据结构的作用是:

Postgresql backend processes can't see each other's memory directly, nor can the postmaster see into PostgreSQL backend process memory. Yet they need some way to communicate and co-ordinate, and the postmaster needs a way to keep track of them.

简单来说作用是为了进程间协同和通讯以及postmaster的跟踪.


struct PGPROC
{
    
    //proc->links必须是结构体的第一个域(参考ProcSleep,ProcWakeup...等)
    //如进程在链表中,这是链表的链接
    SHM_QUEUE   links;          
    //持有该PGPROC的procglobal链表数组
    PGPROC    **procgloballist; 
    //可以休眠的信号量
    PGSemaphore sem;            
    //状态为:STATUS_WAITING, STATUS_OK or STATUS_ERROR
    int         waitStatus;     
    //进程通用的latch
    Latch       procLatch;      
    //运行中的进程正在执行的最高层的事务本地ID,如无运行则为InvalidLocalTransactionId
    LocalTransactionId lxid;    
    //后台进程的ID,如为虚拟事务则为0
    int         pid;            
    int         pgprocno;

    
    //------------ 这些域在进程正在启动时为0
    //已分配的后台进程的backend ID
    BackendId   backendId;      
    //该进程使用的数据库ID
    Oid         databaseId;     
    //使用该进程的角色ID
    Oid         roleId;         
    //该进程使用的临时schema OID
    Oid         tempNamespaceId;    
    //如后台进程,则为T
    bool        isBackgroundWorker; 

    
    bool        recoveryConflictPending;

    
    //-------------- 进程正在等待的LWLock相关信息
    //等待LW lock,为T
    bool        lwWaiting;      
    //正在等的LWLock锁模式
    uint8       lwWaitMode;     
    //等待链表中的位置
    proclist_node lwWaitLink;   

    
    //-------------- 支持条件变量
    //CV等待链表中的位置
    proclist_node cvWaitLink;   

    
    //-------------- 进程正在等待的锁信息
    
    //如没有在等待,则waitLock和waitProcLock为NULL
    //休眠...等待的锁对象
    LOCK       *waitLock;       
    //等待锁的每个持锁人信息
    PROCLOCK   *waitProcLock;   
    //等待的所类型
    LOCKMODE    waitLockMode;   
    //该进程已持有锁的类型位掩码
    LOCKMASK    heldLocks;      

    
    //--------------------- 
    //等待该LSN或者更高的LSN
    XLogRecPtr  waitLSN;        
    //同步复制的等待状态
    int         syncRepState;   
    //如进程处于syncrep队列中,则该值保存链表链接
    SHM_QUEUE   syncRepLinks;   

    
    SHM_QUEUE   myProcLocks[NUM_LOCK_PARTITIONS];
    //子事务的XIDs
    struct XidCache subxids;    

    
    
    //支持XID分组清除
    //如属于等待XID清理的ProcArray组,则为T
    bool        procArrayGroupMember;
    
    //等待XID清理的下一个ProcArray组编号
    pg_atomic_uint32 procArrayGroupNext;

    
    TransactionId procArrayGroupMemberXid;
    //进程的等待信息
    uint32      wait_event_info;    

    
    //--------------- 支持组事务状态更新
    //clog组成员,则为T
    bool        clogGroupMember;    
    //下一个clog组成员
    pg_atomic_uint32 clogGroupNext; 
    //clog组成员事务ID
    TransactionId clogGroupMemberXid;   
    //clog组成员的事务状态
    XidStatus   clogGroupMemberXidStatus;   
    //属于clog组成员的事务ID的clog page
    int         clogGroupMemberPage;    
    //clog组成员已提交记录的WAL位置
    XLogRecPtr  clogGroupMemberLsn; 

    
    //每一个后台进程一个LWLock.保护下面的域字段(非组字段)
    LWLock      backendLock;

    
    //---------- 锁管理数据,记录该后台进程以最快路径获得的锁
    //每一个fast-path slot的锁模式
    uint64      fpLockBits;     
    //rel oids的slots
    Oid         fpRelId[FP_LOCK_SLOTS_PER_BACKEND]; 
    //是否持有fast-path VXID锁
    bool        fpVXIDLock;     
    //fast-path VXID锁的lxid
    LocalTransactionId fpLocalTransactionId;    

    
    //--------- 支持锁组.
    //          在组leader中使用LockHashPartitionLockByProc获取LWLock保护这些域
    //锁组的leader,如果"我"是其中一员
    PGPROC     *lockGroupLeader;    
    //如果"我"是leader,这是成员的链表
    dlist_head  lockGroupMembers;   
    //成员连接,如果"我"是其中一员
    dlist_node  lockGroupLink;  
};

MyProc
每个进程都有一个全局变量:MyProc

extern PGDLLIMPORT PGPROC *MyProc;
extern PGDLLIMPORT struct PGXACT *MyPgXact;

二、源码解读

N/A

三、跟踪分析

启动两个Session,执行同样的SQL语句:

insert into t_wal_partition(c1,c2,c3) VALUES(0,'HASH0','HAHS0');

Session 1
启动gdb,开启跟踪

(gdb) b XLogInsertRecord
Breakpoint 1 at 0x54d122: file xlog.c, line 970.
(gdb) c
Continuing.

Breakpoint 1, XLogInsertRecord (rdata=0xf9cc70 <hdr_rdt>, fpw_lsn=0, flags=1 '\001') at xlog.c:970
970     XLoGCtlInsert *Insert = &XLogCtl->Insert;

查看内存中的数据结构

(gdb) p *MyProc
$3 = {links = {prev = 0x0, next = 0x0}, procgloballist = 0x7fa79c087c98, sem = 0x7fa779fc81b8, waitStatus = 0, procLatch = {
    is_set = 0, is_shared = true, owner_pid = 1398}, lxid = 3, pid = 1398, pgprocno = 99, backendId = 3, 
  databaseId = 16402, roleId = 10, tempNamespaceId = 0, isBackgroundWorker = false, recoveryConflictPending = false, 
  lwWaiting = false, lwWaitMode = 0 '\000', lwWaitLink = {next = 0, prev = 0}, cvWaitLink = {next = 0, prev = 0}, 
  waitLock = 0x0, waitProcLock = 0x0, waitLockMode = 0, heldLocks = 0, waitLSN = 0, syncRepState = 0, syncRepLinks = {
    prev = 0x0, next = 0x0}, myProcLocks = {{prev = 0x7fa79c09c588, next = 0x7fa79c09c588}, {prev = 0x7fa79c09c598, 
      next = 0x7fa79c09c598}, {prev = 0x7fa79c09c5a8, next = 0x7fa79c09c5a8}, {prev = 0x7fa79c09c5b8, 
      next = 0x7fa79c09c5b8}, {prev = 0x7fa79c09c5c8, next = 0x7fa79c09c5c8}, {prev = 0x7fa79c09c5d8, 
      next = 0x7fa79c09c5d8}, {prev = 0x7fa79c09c5e8, next = 0x7fa79c09c5e8}, {prev = 0x7fa79c09c5f8, 
      next = 0x7fa79c09c5f8}, {prev = 0x7fa79c09c608, next = 0x7fa79c09c608}, {prev = 0x7fa79c09c618, 
      next = 0x7fa79c09c618}, {prev = 0x7fa79c09c628, next = 0x7fa79c09c628}, {prev = 0x7fa79c09c638, 
      next = 0x7fa79c09c638}, {prev = 0x7fa79c09c648, next = 0x7fa79c09c648}, {prev = 0x7fa79c09c658, 
      next = 0x7fa79c09c658}, {prev = 0x7fa79c09c668, next = 0x7fa79c09c668}, {prev = 0x7fa79be25e70, 
      next = 0x7fa79be25e70}}, subxids = {xids = {0 <repeats 64 times>}}, procArrayGroupMember = false, 
  procArrayGroupNext = {value = 2147483647}, procArrayGroupMemberXid = 0, wait_event_info = 0, clogGroupMember = false, 
  clogGroupNext = {value = 2147483647}, clogGroupMemberXid = 0, clogGroupMemberXidStatus = 0, clogGroupMemberPage = -1, 
  clogGroupMemberLsn = 0, backendLock = {tranche = 58, state = {value = 536870912}, waiters = {head = 2147483647, 
      tail = 2147483647}}, fpLockBits = 196027139227648, fpRelId = {0, 0, 0, 0, 0, 2679, 2610, 2680, 2611, 17043, 17040, 
    17037, 17034, 17031, 17028, 17025}, fpVXIDLock = true, fpLocalTransactionId = 3, lockGroupLeader = 0x0, 
  lockGroupMembers = {head = {prev = 0x7fa79c09c820, next = 0x7fa79c09c820}}, lockGroupLink = {prev = 0x0, next = 0x0}}

注意:lwWaiting值为false,表示没有在等待LW Lock

Session 2
启动gdb,开启跟踪

(gdb) b heap_insert
Breakpoint 2 at 0x4df4d1: file heapam.c, line 2449.
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00007fa7a7ee7a0b in futex_abstimed_wait (cancel=true, private=<optimized out>, abstime=0x0, expected=0, 
    futex=0x7fa779fc8138) at ../nptl/sysdeps/unix/sysv/linux/sem_waitcommon.c:43
43        err = lll_futex_wait (futex, expected, private);

暂无法进入heap_insert
查看内存中的数据结构

(gdb) p *MyProc
$36 = {links = {prev = 0x0, next = 0x0}, procgloballist = 0x7fa79c087c98, sem = 0x7fa779fc8138, waitStatus = 0, 
  procLatch = {is_set = 1, is_shared = true, owner_pid = 1449}, lxid = 13, pid = 1449, pgprocno = 98, backendId = 4, 
  databaseId = 16402, roleId = 10, tempNamespaceId = 0, isBackgroundWorker = false, recoveryConflictPending = false, 
  lwWaiting = true, lwWaitMode = 0 '\000', lwWaitLink = {next = 114, prev = 2147483647}, cvWaitLink = {next = 0, prev = 0}, 
  waitLock = 0x0, waitProcLock = 0x0, waitLockMode = 0, heldLocks = 0, waitLSN = 0, syncRepState = 0, syncRepLinks = {
    prev = 0x0, next = 0x0}, myProcLocks = {{prev = 0x7fa79c09c238, next = 0x7fa79c09c238}, {prev = 0x7fa79c09c248, 
      next = 0x7fa79c09c248}, {prev = 0x7fa79c09c258, next = 0x7fa79c09c258}, {prev = 0x7fa79c09c268, 
      next = 0x7fa79c09c268}, {prev = 0x7fa79c09c278, next = 0x7fa79c09c278}, {prev = 0x7fa79c09c288, 
      next = 0x7fa79c09c288}, {prev = 0x7fa79c09c298, next = 0x7fa79c09c298}, {prev = 0x7fa79c09c2a8, 
      next = 0x7fa79c09c2a8}, {prev = 0x7fa79c09c2b8, next = 0x7fa79c09c2b8}, {prev = 0x7fa79c09c2c8, 
      next = 0x7fa79c09c2c8}, {prev = 0x7fa79c09c2d8, next = 0x7fa79c09c2d8}, {prev = 0x7fa79c09c2e8, 
      next = 0x7fa79c09c2e8}, {prev = 0x7fa79c09c2f8, next = 0x7fa79c09c2f8}, {prev = 0x7fa79c09c308, 
      next = 0x7fa79c09c308}, {prev = 0x7fa79be21870, next = 0x7fa79be21870}, {prev = 0x7fa79c09c328, 
      next = 0x7fa79c09c328}}, subxids = {xids = {0 <repeats 64 times>}}, procArrayGroupMember = false, 
  procArrayGroupNext = {value = 2147483647}, procArrayGroupMemberXid = 0, wait_event_info = 16777270, 
  clogGroupMember = false, clogGroupNext = {value = 2147483647}, clogGroupMemberXid = 0, clogGroupMemberXidStatus = 0, 
  clogGroupMemberPage = -1, clogGroupMemberLsn = 0, backendLock = {tranche = 58, state = {value = 536870912}, waiters = {
      head = 2147483647, tail = 2147483647}}, fpLockBits = 196027139227648, fpRelId = {0, 0, 0, 0, 0, 2655, 2603, 2680, 
    2611, 17043, 17040, 17037, 17034, 17031, 17028, 17025}, fpVXIDLock = true, fpLocalTransactionId = 13, 
  lockGroupLeader = 0x0, lockGroupMembers = {head = {prev = 0x7fa79c09c4d0, next = 0x7fa79c09c4d0}}, lockGroupLink = {
    prev = 0x0, next = 0x0}}

注意:
lwWaiting值为true,正在等待Session 1的LWLock.
lwWaitLink = {next = 114, prev = 2147483647},其中next = 114,这里的114是指全局变量ProcGlobal(类型为PROC_HDR)->allProcs数组下标为114的ITEM.

(gdb) p ProcGlobal->allProcs[114]
$41 = {links = {prev = 0x0, next = 0x0}, procgloballist = 0x0, sem = 0x7fa779fc8938, waitStatus = 0, procLatch = {
    is_set = 0, is_shared = true, owner_pid = 1351}, lxid = 0, pid = 1351, pgprocno = 114, backendId = -1, databaseId = 0, 
  roleId = 0, tempNamespaceId = 0, isBackgroundWorker = false, recoveryConflictPending = false, lwWaiting = true, 
  lwWaitMode = 1 '\001', lwWaitLink = {next = 2147483647, prev = 98}, cvWaitLink = {next = 0, prev = 0}, waitLock = 0x0, 
  waitProcLock = 0x0, waitLockMode = 0, heldLocks = 0, waitLSN = 0, syncRepState = 0, syncRepLinks = {prev = 0x0, 
    next = 0x0}, myProcLocks = {{prev = 0x7fa79c09f738, next = 0x7fa79c09f738}, {prev = 0x7fa79c09f748, 
      next = 0x7fa79c09f748}, {prev = 0x7fa79c09f758, next = 0x7fa79c09f758}, {prev = 0x7fa79c09f768, 
      next = 0x7fa79c09f768}, {prev = 0x7fa79c09f778, next = 0x7fa79c09f778}, {prev = 0x7fa79c09f788, 
      next = 0x7fa79c09f788}, {prev = 0x7fa79c09f798, next = 0x7fa79c09f798}, {prev = 0x7fa79c09f7a8, 
      next = 0x7fa79c09f7a8}, {prev = 0x7fa79c09f7b8, next = 0x7fa79c09f7b8}, {prev = 0x7fa79c09f7c8, 
      next = 0x7fa79c09f7c8}, {prev = 0x7fa79c09f7d8, next = 0x7fa79c09f7d8}, {prev = 0x7fa79c09f7e8, 
      next = 0x7fa79c09f7e8}, {prev = 0x7fa79c09f7f8, next = 0x7fa79c09f7f8}, {prev = 0x7fa79c09f808, 
      next = 0x7fa79c09f808}, {prev = 0x7fa79c09f818, next = 0x7fa79c09f818}, {prev = 0x7fa79c09f828, 
      next = 0x7fa79c09f828}}, subxids = {xids = {0 <repeats 64 times>}}, procArrayGroupMember = false, 
  procArrayGroupNext = {value = 0}, procArrayGroupMemberXid = 0, wait_event_info = 16777270, clogGroupMember = false, 
  clogGroupNext = {value = 0}, clogGroupMemberXid = 0, clogGroupMemberXidStatus = 0, clogGroupMemberPage = 0, 
  clogGroupMemberLsn = 0, backendLock = {tranche = 58, state = {value = 536870912}, waiters = {head = 2147483647, 
      tail = 2147483647}}, fpLockBits = 0, fpRelId = {0 <repeats 16 times>}, fpVXIDLock = false, fpLocalTransactionId = 0, 
  lockGroupLeader = 0x0, lockGroupMembers = {head = {prev = 0x7fa79c09f9d0, next = 0x7fa79c09f9d0}}, lockGroupLink = {
    prev = 0x0, next = 0x0}}

“PostgreSQL中PGPROC数据结构分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL中PGPROC数据结构分析

本文链接: https://lsjlt.com/news/64719.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • PostgreSQL中PGPROC数据结构分析
    本篇内容介绍了“PostgreSQL中PGPROC数据结构分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成...
    99+
    2024-04-02
  • 分析PostgreSQL中的数据结构HTAB
    这篇文章主要讲解了“分析PostgreSQL中的数据结构HTAB”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“分析PostgreSQL中的数据结构HTAB”...
    99+
    2024-04-02
  • PostgreSQL中WAL文件结构分析
    本篇内容介绍了“PostgreSQL中WAL文件结构分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!WA...
    99+
    2024-04-02
  • PostgreSQL中PlannedStmt结构的日志分析
    这篇文章主要介绍了PostgreSQL中PlannedStmt结构的日志分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。APPEND-&g...
    99+
    2024-04-02
  • PostgreSQL中WAL segment file内部结构分析
    本篇内容介绍了“PostgreSQL中WAL segment file内部结构分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔...
    99+
    2024-04-02
  • PostgreSQL数据库体系结构-存储结构
    PostgreSQL数据库体系结构-存储结构 数据库聚簇逻辑结构(Logical Structure of Database Cluster) database cluster--数据库聚簇,是一组数据库的集合,而不是多个数据库服务器 ...
    99+
    2021-08-02
    PostgreSQL数据库体系结构-存储结构
  • Java中数据结构的示例分析
    这篇文章将为大家详细讲解有关Java中数据结构的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.1.1.       增量内存分配 ArrayList 、 Hash...
    99+
    2023-06-03
  • postgresql数据库体系结构
    postgresql数据库是由:连接管理系统(系统控制器)、编译执行系统、存储管理系统、事务系统、系统表 五大部分组成。 ①:连接管理系统:接收外部操作对系统的请求,对操作请求进行预处理和分发,起...
    99+
    2024-04-02
  • Android数据结构全面总结分析
    前言 这次算一个总结,我们平时都会用到各种各样的数据结构,但是可能从未看过它们内部是如何去实现的。只有了解了它们内部大概的一个实现原理,才能在不同的场景中能选出最适合这个场景的数据结...
    99+
    2022-12-08
    Android 数据结构 Android 数据结构总结分析
  • AndroidMap数据结构全面总结分析
    目录前言MapArrayMapTreeMapHashMap总结前言 上一篇讲了Collection、Queue和Deque、List或Set,没看的朋友可以去简单看看,这一篇主要讲和...
    99+
    2022-12-08
    Android Map数据结构 Android Map
  • python数据结构算法分析
    目录1.算法分析的定义2.大O记法3.不同算法的大O记法3.1清点法3.2排序法3.3蛮力法3.4计数法4.列表和字典操作的复杂度4.1列表4.2字典前文学习: python数据类型...
    99+
    2024-04-02
  • JavaScript数据结构中串的示例分析
    这篇文章将为大家详细讲解有关JavaScript数据结构中串的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体如下:类似于线性表的顺序存储结构,用一组地址连续的...
    99+
    2024-04-02
  • C++数据结构中list的示例分析
    小编给大家分享一下C++数据结构中list的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!前言list相较于vector来说会显得复杂,它的好处是在任意位置插入,删除都是一个O(1)的时间复杂度。一、list的节点...
    99+
    2023-06-25
  • Java数据结构中图的示例分析
    这篇文章给大家分享的是有关Java数据结构中图的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。有向图有向图的定义及相关术语定义∶ 有向图是一副具有方向性的图,是由一组顶点和一组有方向的边组成的,每条方向的...
    99+
    2023-06-29
  • Python Pandas中的数据结构实例分析
    今天小编给大家分享一下Python Pandas中的数据结构实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。...
    99+
    2023-07-02
  • PostgreSQL中的Tuplesortstate数据结构是怎样的
    本篇内容主要讲解“PostgreSQL中的Tuplesortstate数据结构是怎样的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中的Tu...
    99+
    2024-04-02
  • 分析Java数据结构与算法
    本篇内容主要讲解“分析Java数据结构与算法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析Java数据结构与算法”吧!1.什么是二叉树二叉树:就是每个节点都...
    99+
    2024-04-02
  • JavaScript数据结构Number实例分析
    本文小编为大家详细介绍“JavaScript数据结构Number实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“JavaScript数据结构Number实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-06-29
  • PostgreSQL 的分槽页结构
    在PostgreSQL中,表存储在堆文件中,这些文件采用分槽的页(slotted-page)格式,该结构便于存储变长记录。 尽管这种架构允许向一页中添加或删除元组,基于PostgreSQL的MVCC方式,这...
    99+
    2024-04-02
  • Redis中数据结构的底层实现分析
    Redis中数据结构的底层实现分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1、概述Redis是一个开源的使用ANSI C...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作