Octets Golang.Analyse du code source du tampon

Octets Golang.Analyse du code source du tampon

En tant que cache efficace, Buffer prend en charge les opérations de lecture, d'écriture et d'annulation de lecture, et peut être utilisé pour la mise en cache et l'analyse de flux d'octets. Voici une brève analyse de son implémentation du code source.

La version source de cet article est go1.16.3 linux/amd64

règle d'auto-croissance

Le tampon peut augmenter sa propre longueur lorsque la longueur est insuffisante. Sa fonction de croissance principale est grow(n int) intune fonction privée et le code source se trouve à go/src/bytes/buffer.gola ligne 117 :

// grow grows the buffer to guarantee space for n more bytes.
// It returns the index where bytes should be written.
// If the buffer can't grow it will panic with ErrTooLarge.
func (b *Buffer) grow(n int) int {
    
    
	m := b.Len()
	// If buffer is empty, reset to recover space.
	if m == 0 && b.off != 0 {
    
    
		b.Reset()
	}
	// Try to grow by means of a reslice.
	if i, ok := b.tryGrowByReslice(n); ok {
    
    
		return i
	}
	if b.buf == nil && n <= smallBufferSize {
    
    
		b.buf = make([]byte, n, smallBufferSize)
		return 0
	}
	c := cap(b.buf)
	if n <= c/2-m {
    
    
		// We can slide things down instead of allocating a new
		// slice. We only need m+n <= c to slide, but
		// we instead let capacity get twice as large so we
		// don't spend all our time copying.
		copy(b.buf, b.buf[b.off:])
	} else if c > maxInt-c-n {
    
    
		panic(ErrTooLarge)
	} else {
    
    
		// Not enough space anywhere, we need to allocate.
		buf := makeSlice(2*c + n)
		copy(buf, b.buf[b.off:])
		b.buf = buf
	}
	// Restore b.off and len(b.buf).
	b.off = 0
	b.buf = b.buf[:m+n]
	return m
}

Parmi eux, tryGrowByReslicela fonction de est principalement d' initialiser un nouvel espace de n octets pour que la longueur respecte la norme lorsque la b.bufcapacité répond à la demande mais que la longueur ne répond pas à la demande. Le code source est le suivant :len

// tryGrowByReslice is a inlineable version of grow for the fast-case where the
// internal buffer only needs to be resliced.
// It returns the index where bytes should be written and whether it succeeded.
func (b *Buffer) tryGrowByReslice(n int) (int, bool) {
    
    
	if l := len(b.buf); n <= cap(b.buf)-l {
    
    
		b.buf = b.buf[:l+n]
		return l, true
	}
	return 0, false
}

Au lieu de cela , il a simplement été ajouté avant makeSliceet le code source n'a pas été publié.make([]byte, n)defer

On voit que grow(n)la fonction de est de s'assurer que le cache peut libérer au moins n octets d'espace libre. La fonction est d'abord appelée tryGrowByReslicepour déterminer b.bufsi l'espace restant répond aux exigences et initialiser l'espace d'octets de n bits ; sinon, essayez de réorganiser les éléments existants pour obtenir suffisamment d'espace ; si le réarrangement ne peut pas résoudre le problème, alors Réallouez un plus grand bloc de mémoire.
En raison de growce mécanisme de la fonction, Buffer est similaire à une file d'attente circulaire auto-croissante dans certaines caractéristiques, son "pointeur arrière" est équivalent len(b.buf)et son "pointeur avant" est équivalent b.off. Lorsqu'une opération d'écriture (équivalente à entrer dans la file d'attente), len(b.buf)il grandit ; lorsqu'une opération de lecture se produit (équivalent à sortir de la file d'attente), b.offil avance ; contrairement à la file d'attente circulaire, lorsque le Buffer est sur le point de déborder faussement, le "pointeur arrière" ne ne pas se déplacer vers la tête Au lieu de reboucler à la tête, b.offtous les éléments inutilisés sont glissés du début vers la tête. Bien que la complexité temporelle O(m) de l'opération de traduction globale soit supérieure à celle de la boucle de pointeur O(1), parce que copyla fonction est une fonction intégrée à la couche inférieure, cela ne prend en fait pas beaucoup de temps ; et dans Afin de réduire davantage la surcharge causée par la traduction fréquente, le critère de "faux débordement" n'est pas celui actuel cap, mais caple double de celui actuel. Ici, nous pouvons également voir la logique de conception de golang, c'est-à-dire que, sous l'hypothèse que le matériel informatique moderne est suffisamment développé, le développement de logiciels peut être grandement facilité en sacrifiant de manière appropriée la surcharge de ressources, ce qui est tout le contraire de l'idée de conception de C /C++.

lire et annuler la lecture

Buffer prend en charge Read, ReadByteet ReadRunetrois opérations de lecture majeures, qui Readsont irréversibles ReadByteet ReadRunepeuvent être annulées une fois.
Après avoir lu n octets, Buffer avancera b.offde n octets. La soi-disant annulation consiste essentiellement à b.offramener les données à la position avant l'opération de lecture. En termes d'implémentation spécifique, UnreadByteoui b.off--, UnreadRunec'est un b.lastReadoctet avant.
Voici un exemple simple d'application pour annuler la lecture : lors de la transmission de données en continu, vous devez trouver l'en-tête de synchronisation, vous pouvez lire un octet et le comparer, s'il s'agit d'un en-tête de synchronisation, continuez à lire ; si ce n'est pas une synchronisation en-tête, annulez la lecture, afin que les données soient conservées telles quelles et transmises au lien suivant qui a besoin des données.

Tronquer et réinitialiser

  • Buffer.Truncate(n int)Le cache peut être tronqué pour ne garder que ce qui est nécessaire. Cette fonction synchronisera les propriétés modifiées b.bufet . Le code source est le suivant :lencap
// Truncate discards all but the first n unread bytes from the buffer
// but continues to use the same allocated storage.
// It panics if n is negative or greater than the length of the buffer.
func (b *Buffer) Truncate(n int) {
    
    
	if n == 0 {
    
    
		b.Reset()
		return
	}
	b.lastRead = opInvalid
	if n < 0 || n > b.Len() {
    
    
		panic("bytes.Buffer: truncation out of range")
	}
	b.buf = b.buf[:b.off+n]
}
  • Buffer.Reset()Va complètement réinitialiser b.bufet b.off, son code source est très simple :
// Reset resets the buffer to be empty,
// but it retains the underlying storage for use by future writes.
// Reset is the same as Truncate(0).
func (b *Buffer) Reset() {
    
    
	b.buf = b.buf[:0]
	b.off = 0
	b.lastRead = opInvalid
}

Supongo que te gusta

Origin blog.csdn.net/liuqixuan1994/article/details/119734450
Recomendado
Clasificación