Skip to content

Commit

Permalink
add: sync pool
Browse files Browse the repository at this point in the history
  • Loading branch information
Ja7ad committed Jan 4, 2023
1 parent b8ea45a commit 1d1a82a
Showing 1 changed file with 109 additions and 0 deletions.
109 changes: 109 additions & 0 deletions content/chapter 3/3.3-sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ weight: 5003
- `RWMutex` : با استفاده از این می توانید به چندین گوروتین اجازه خواندن دهید ولی فقط یک گوروتین می تواند بنویسد در یک زمان.
- `WaitGroup`: یک هماهنگ کننده گوروتین می باشد برای اینکه ترتیب عملیات ها در هنگام همزمانی رعایت شود.
- `Once`: این اجازه می دهد یک تابع حداکثر یک بار اجرا شود.
- **Pool:** مجموعه از آبجکت های موقت که امکان ذخیره و دریافت دارند بدون اینکه بخشی از حافظه را اشتغال کنند.

{{< hint info >}}
توجه کنید که پکیج `sync` فقط و فقط برای مدیریت و همگام سازی دسترسی های گوروتین ها به یک داده مشترک استفاده می شود.
Expand Down Expand Up @@ -88,3 +89,111 @@ Incrementing: 4
در پکیج `sync` یک تایپ به نام `RWMutex` وجود دارد که عملیات خواندن و نوشتن برروی یک داده مشترک را {{< tooltip text="همگام سازی" note="synchronize" >}} می کند. شما می توانید به چندین گوروتین اجازه خواندن یک داده مشترک را بدهید ولی فقط یک گوروتین می تواند عملیات نوشتن را برروی آن داده مشترک را انجام دهد.


## 3.3.3 WaitGroup


## 3.3.4 Once


## 3.3.5 Pool

در نسخه ۱.۳ زبان گو امکانی تایپی به نام Pool در پکیج sync که امکان ایجاد استخر آبجکت ها بطور موقت بدون اینکه بخواهد بخشی از حافظه را اشتغال کند اضافه شد.

هر آبجکتی که در Pool ذخیره شود بطور خودکار در هرزمانی بدون اینکه اطلاع رسانی کند حذف می شود.

```go
package main

import (
"bytes"
"io"
"os"
"sync"
"time"
)

var bufPool = sync.Pool{
New: func() any {
// The Pool's New function should generally only return pointer
// types, since a pointer can be put into the return interface
// value without an allocation:
return new(bytes.Buffer)
},
}

// timeNow is a fake version of time.Now for tests.
func timeNow() time.Time {
return time.Unix(1136214245, 0)
}

func Log(w io.Writer, key, val string) {
b := bufPool.Get().(*bytes.Buffer)
b.Reset()
// Replace this with time.Now() in a real logger.
b.WriteString(timeNow().UTC().Format(time.RFC3339))
b.WriteByte(' ')
b.WriteString(key)
b.WriteByte('=')
b.WriteString(val)
w.Write(b.Bytes())
bufPool.Put(b)
}

func main() {
Log(os.Stdout, "path", "/search?q=flowers")
}
```

```shell
$ go run main.go
2006-01-02T15:04:05Z path=/search?q=flowers
```

در بالا ما یک متغیر به نام bufPool ایجاد کردیم که یک آبجکت از نوع bytes.Buffer ایجاد می کند. سپس داخل تابع Log ما با استفاده از متد Get آبجکت مورد نظر را از Pool خارج و داخل متغیر b قرار دادیم و پس از آن عملیات لازم را برروی Buffer انجام و در نهایت با استفاده از متد Put آبجکت را به Pool اضافه کردیم. حالا اتفاقی که صورت گرفته ما عملیاتی که نیاز داشتیم را برروی آبجکت انجام دادیم بدون اینکه بخوایم بخشی از حافظه را درگیر کنیم.


**یک نمونه بنچمارک در خصوص Pool**

```go
type Person struct {
Age int
}

var personPool = sync.Pool{
New: func() interface{} { return new(Person) },
}

func BenchmarkWithoutPool(b *testing.B) {
var p *Person
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < 10000; j++ {
p = new(Person)
p.Age = 23
}
}
}

func BenchmarkWithPool(b *testing.B) {
var p *Person
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < 10000; j++ {
p = personPool.Get().(*Person)
p.Age = 23
personPool.Put(p)
}
}
}
```


```shell
BenchmarkWithoutPool
BenchmarkWithoutPool-8 160698 ns/op 80001 B/op 10000 allocs/op

BenchmarkWithPool
BenchmarkWithPool-8 191163 ns/op 0 B/op 0 allocs/op
```

0 comments on commit 1d1a82a

Please sign in to comment.