Golang structure of primary data types

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Map

The Golang map is implemented using a hash table. We know that the hash mapping must solve a problem: how to effectively avoid the hash collision. There are some ways to avoid hash collisions: Open address method, link address method, and create a public overflow area. The hash table uses a chain address to solve the collision problem.
Let's look at the underlying data structure defined by Golang for map:

type hmap struct {    count     int     flags     uint8    B         uint8      noverflow uint16     hash0     uint32     buckets    unsafe.Pointer    oldbuckets unsafe.Pointer     nevacuate  uintptr            overflow *[2]*[]*bmap}

The size of the hash table is determined by the B field, and the size is: 2^B . countis provided to len() the use. There is one and one in the struct that buckets oldbuckets is used to achieve incremental expansion. The normal use of the case oldbuckets is empty, only when the expansion of the time is not empty. When you expand, oldbuckets point to buckets the address that you pointed to earlier, and then buckets point to the address after the re-expansion, which is twice times the size of the last time.

struct Bucket{    uint8  tophash[BUCKETSIZE]; // hash值的高8位....低位从bucket的array定位到bucket    Bucket *overflow;           // 溢出桶链表,如果有    byte   data[1];             // BUCKETSIZE keys followed by BUCKETSIZE values};

Here is a map of maps that is generally drawn:


Map.png

The key of the hash (key) low 8 bits as the bucket position index information, hit the corresponding subscript, the use of high 8 bits in the first bucket inside the inside tophash match key is within the Bucke, if not in the next bucket inside the search, If the value is removed, return it. As for the Hashtable expansion problem, the Golang source package gives a table of expansion parameters:

LOAD    %overflow  bytes/entry     hitprobe    missprobe4.00         2.13        20.77         3.00         4.004.50         4.05        17.30         3.25         4.505.00         6.85        14.77         3.50         5.005.50        10.55        12.94         3.75         5.506.00        15.27        11.67         4.00         6.006.50        20.90        10.79         4.25         6.507.00        27.14        10.15         4.50         7.007.50        34.03         9.73         4.75         7.508.00        41.10         9.40         5.00         8.00

Slice

The same different slices of the underlying array are references to this data, so changing the underlying data of the slice will follow the change, and if you don't want the underlying data to change, you can copy the tiles out and then modify the array after copy (remember).
The structure of the Golang source package in Slice is as follows:

struct    Slice{    byte*    array;    uintgo    len;       uintgo    cap;};

The most common operations that involve slice are: append. In this process will be related to slice expansion, the principle of expansion is:

1. 如果新的大小是当前大小2倍以上,则大小增长为新大小2. 否则循环以下操作:如果当前大小小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新大小。

Slice also has a common problem: the difference between new and make. We all know that initializing or instantiating a slice variable, you can use new or make, and when to use new, when do you use make?
New (T) returns a *t that returns a pointer that can be implicitly de-referenced. and make (t, args) returns a normal T. In general, there are implicit pointers inside T. In a word, new returns a pointer to the cleared 0 memory, and make returns a complex structure.

Channel

Channel is a top citizen in the go language, everything can be loaded, parameters and return values and other types of data. The go language has a classic quote: "To allow communication to share memory instead of shared memory to communicate", let's look at the structure of the channel:

struct    Hchan{    uintgo    qcount;            // 队列q中的总数据数量    uintgo    dataqsiz;         // 环形队列q的数据大小    uint16    elemsize;    bool    closed;    uint8    elemalign;    Alg*    elemalg;          uintgo    sendx;            // 发送index    uintgo    recvx;            // 接收index    WaitQ    recvq;            // 因recv而阻塞的等待队列    WaitQ    sendq;           // 因send而阻塞的等待队列    Lock;};

Where Recvq is a goroutine queue that is blocked by reads, SENDQ is a goroutine queue that is blocked by writing. The head of the queue is:

struct    WaitQ{    SudoG*    first;    SudoG*    last;};

The structure of the member variables in the queue is:

struct    SudoG{    G*    g;                 // g and selgen constitute    uint32    selgen;        // a weak pointer to g    SudoG*    link;    int64    releasetime;    byte*    elem;           // data element};

When sending data, determine the type of channel, if there is a buffer, determine if the channel has space, and then from the waiting channel to obtain the receiver in the channel, if the receiver, the object is passed directly to the receiver, Then the receiver's go into the run G queue where p is located, the sending process is completed, if not taken to the receiver, then the sender enqueue to send the channel, the sender into the blocking state, the buffer channel needs to first determine whether the channel buffer has space, If the buffer space is full, the sender is enqueue to send the channel, the sender enters the blocking state if the buffer space is not full, then the element is copied to the buffer, then the sender will not enter the blocking state, and finally try to wake up a recipient in the waiting queue. (this summary is from: https://zhuanlan.zhihu.com/p/27295229)

Receive channel and send similar to first also determine the type of channel, and then if there is a buffer channel to determine whether there are elements in the buffer, then from the channel to obtain the recipient, if fetched, then directly from the receiver to obtain the element, and wake the sender, the reception process is complete, If the receiver is not fetched, blocking the current goroutine and waiting for the sender to wake up, if it is a buffered channel needs to determine whether there are elements in the buffer, buffering is empty, blocking the current goroutine and waiting for the sender to wake up, buffer if not empty, then take out the first element in the buffer , and then try to wake up a sender in the channel. (this summary is from: https://zhuanlan.zhihu.com/p/27295229)

Interface, select, ..., are the data structures that are worth analyzing, and then add the following ... end~

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.