Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update 3.7-select.md #280

Merged
merged 6 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions content/chapter 3/3.7-select.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ From goOne goroutine
From goTwo goroutine
```

در کد فوق ما select را داخل یک حلقه fori قرار دادیم و گفتیم مقدار i کوچکتر از ۲ بود ++i شود. که در هر دو تایم مقدار دریافتی از کانال ها را توانستیم به عنوان خروجی چاپ کنیم.
در کد فوق ما select را داخل یک حلقه for قرار دادیم و گفتیم اگر مقدار i کوچکتر از ۲ بود ++i شود. که در هر دو تایم مقدار دریافتی از کانال ها را توانستیم به عنوان خروجی چاپ کنیم.


همانطور که قبلا گفتیم اگر شما داخل select یک case ی را بزارید که هیچ اطلاعات از کانال دریافت نکند ممکن است برنامه شما کاملا بلاک شود و با خطای deadlock مواجه شوید.
همانطور که قبلا گفتیم اگر شما داخل select یک case را بزارید که هیچ اطلاعات از کانال دریافت نکند ممکن است برنامه شما کاملا بلاک شود و با خطای deadlock مواجه شوید.

```go
package main
Expand All @@ -131,7 +131,7 @@ fatal error: all goroutines are asleep - deadlock!

## 3.7.1 نحوه کنترل عملیات های کانال با select

در بالا در خصوص select توضیح دادیم که چه کاربردی هایی دارد اما بزارید توضیحات را تکمیل کنیم. وقتی شما قصد دارید از گوروتین و کانال استفاده کنید در اینجا select نقش خیلی پررنگی در کنترل عملیات کانال ها دارد. اینجاست که بحث همزمانی در زبان گو خیلی زیبا می شود. select می تواند بطور همزمان داده را از کانال دریافت کند و برای اجرا سایر عملیات آماده کند. بنابراین select همراه با کانال و گوروتین خیلی ابزار قدرتمندی می شود برای کنترل و مدیریت همگام سازی و همزمانی.
در بالا در خصوص select توضیح دادیم که چه کاربردی هایی دارد اما بزارید توضیحات را تکمیل کنیم. وقتی شما قصد دارید از گوروتین و کانال استفاده کنید در اینجا select نقش خیلی پررنگی در کنترل عملیات کانال ها دارد. اینجاست که بحث همزمانی در زبان گو خیلی زیبا می شود. select می تواند بطور همزمان داده را از کانال دریافت کند و برای اجرا سایر عملیات آماده کند. بنابراین select همراه با کانال و گوروتین خیلی ابزار قدرتمندی برای کنترل و مدیریت همگام سازی و همزمانی می شود.

### 3.7.1.1 عملیات ارسال با select

Expand Down Expand Up @@ -170,7 +170,7 @@ $ go run main.go
To goTwo goroutine
```

در کد فوق ما با استفاده از یکی از case های select داده ای را داخل کانال ریختیم و آن داده را داخل گوروتین تابع goTwo دریافت کردیم و پس آن چاپ کردیم مقدار دریافتی را.
در کد فوق ما با استفاده از یکی از case های select دادهای را داخل کانال ریختیم و آن داده را داخل گوروتین تابع goTwo دریافت کردیم و پس آن مقدار دریافتی را چاپ کردیم.


## 3.7.2 استفاده از default در select
Expand Down Expand Up @@ -204,7 +204,7 @@ Default statement executed

## 3.7.3 مسدود سازی select با استفاده از timeout

شما می توانید یک select را با استفاده از timeout بطور موقت تا یک بازده زمانی مسدود کنید. که اینکار توسط تابع [After](https://pkg.go.dev/time#Time.After) داخل پکیج time صورت میگیرد.
شما می توانید یک select را با استفاده از timeout بطور موقت تا یک بازه زمانی مسدود کنید. که اینکار توسط تابع [After](https://pkg.go.dev/time#Time.After) داخل پکیج time صورت میگیرد.

```go
func After(d Duration) <-chan Time
Expand Down Expand Up @@ -267,7 +267,7 @@ fatal error: all goroutines are asleep - deadlock!

## 3.7.5 استفاده از select در حلقه بینهایت

ما می توانیم select را داخل یک حلقه بینهایت قرار دهیم تا برای همیشه از case ها چندتا داده بواسطه کانال دریافت کنیم و عملیاتی را انجام دهیم یا اینکه اگر قصد داریم که از هر یک از case ها داده ای را دریافت کردیم حلقه را متوقف کنیم اینکار را هم بواسطه return می توانیم انجام دهیم.
ما می توانیم select را داخل یک حلقه بینهایت قرار دهیم تا برای همیشه از case ها چندتا داده را بواسطه کانال دریافت کنیم و عملیاتی را انجام دهیم یا اینکه اگر قصد داریم که از هر یک از case ها دادهای را دریافت کردیم حلقه را متوقف کنیم اینکار را هم بواسطه return می توانیم انجام دهیم.

```go
package main
Expand Down Expand Up @@ -311,7 +311,7 @@ News: 2
Timeout: News feed finished
```

در کد فوق ما یک کانال بافر نشده با نام news ایجاد کردیم و این کانال را داخل گوروتین newsFeed و تابع printAllNews قرار دادیم. تابع newsFeed یک مقداری را به کانال ارسال می کند. و ما داخل تابع printAllNews بواسطه حلقه بینهایت و select دریافت می کنیم و یکی از case های select عملیات timeout را دارد که بعد ۱ ثانیه حلقه را کاملا متوقف کند.
در کد فوق ما یک کانال بافر نشده با نام news ایجاد کردیم و این کانال را داخل گوروتین newsFeed و تابع printAllNews قرار داده‌ایم. تابع newsFeed یک مقداری را به کانال ارسال می کند. و ما داخل تابع printAllNews بواسطه حلقه بینهایت و select دریافت می کنیم و یکی از case های select عملیات timeout را دارد که بعد ۱ ثانیه حلقه را کاملا متوقف کند.


## 3.7.6 select با یک کانال nil
Expand Down Expand Up @@ -359,7 +359,7 @@ News: 1
Timeout: News feed finished
```

در کد فوق ما داخل `case n := <-news` پس از اینکه مقدار دریافتی را چاپ کردیم اومدی مقدار کانال news را برابر nil قرار دادیم. حال داده ای به اون کانال ارسال شود دیگر نمی توانیم دریافت کنیم و select آن case را بطور کلی نادیده میگیرد.
در کد فوق ما داخل `case n := <-news` پس از اینکه مقدار دریافتی را چاپ کردیم اومدیم مقدار کانال news را برابر nil قرار دادیم. حالا اگر داده‌ای به اون کانال ارسال شود دیگر نمی توانیم دریافت کنیم و select آن case را بطور کلی نادیده میگیرد.

```go
case n := <-news:
Expand Down Expand Up @@ -399,4 +399,4 @@ Before break

```go
fmt.Println("After break")
```
```
12 changes: 6 additions & 6 deletions content/chapter 3/3.8-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ type CancelFunc func()
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
```

حالا سعی با استفاده از مثال زیر بحث لغو کردن را درک کنید :
حالا با استفاده از مثال زیر میتوانید بحث لغو کردن را بهتر درک کنید :

```go
package main
Expand Down Expand Up @@ -296,7 +296,7 @@ defer cancelFunc()

## 3.8.6 تابع context.WithTimeout

تابع WithTimeout یکی از کاربردی ترین context ها را برای ما ایجاد میکند و باعث می شود جلوی طول کشید یک درخواست خارجی یا عملیاتی را بگیرد و درخواست را لغو کند. این تابع همانند تابع WithCancel به شما تابع cancelFunc را می دهد و در عوض از شما یک مدت زمان را میگیرد.
تابع WithTimeout یکی از کاربردی ترین context ها را برای ما ایجاد میکند و باعث می شود جلوی طول کشیدن یک درخواست خارجی یا عملیاتی را بگیرد و درخواست را لغو کند. این تابع همانند تابع WithCancel به شما تابع cancelFunc را می دهد و در عوض از شما یک مدت زمان را میگیرد.

```go
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
Expand Down Expand Up @@ -347,11 +347,11 @@ Gracefully exit
context deadline exceeded
```

در کد فوق ما یک context فرزند با استفاده از تابع WithTimeout ایجاد کردیم و مدت زمان ۳ ثانیه به این تابع پاس دادیم و پس از آن context فرزند به همراه تابع cancelFunc دریافت کردیم. حالا تابع cancel را داخل defer قرار دادیم و cancelCtx را به تابع task1 که داخل گوروتین است پاس دادیم. و یک Sleep به مدت ۴ ثانیه گذاشتیم تابع main کارش اتمام نشود. حال پس از اینکه ۳ ثانیه گذشت داخل select سیگنال cancel را دریافت کردیم و خطای context deadline exceeded که نشان دهنده اتمام شدن مدت زمان هست را چاپ کردیم. و همانطور که متوجه شدید درخواست کلی ما لغو شدش.
در کد فوق ما یک context فرزند با استفاده از تابع WithTimeout ایجاد کردیم و مدت زمان ۳ ثانیه به این تابع پاس دادیم و پس از آن context فرزند به همراه تابع cancelFunc دریافت کردیم. حالا تابع cancel را داخل defer قرار دادیم و cancelCtx را به تابع task1 که داخل گوروتین است پاس داده ایم سپس و یک Sleep به مدت ۴ ثانیه گذاشتیم تا، تابع main کارش تمام نشود. حال پس از اینکه ۳ ثانیه گذشت داخل select سیگنال cancel را دریافت کردیم و خطای context deadline exceeded که نشان دهنده اتمام شدن مدت زمان هست را چاپ کرده ایم. همانطور که متوجه شدید درخواست کلی ما لغو شده.

## 3.8.7 تابع context.WithDeadline

تابع WithDeadline تا حدی شبیه به WithTimeout است اما با این تفاوت که پارامتر زمانی که میگیرد از نوع time.Time است و مدت زمانی که میگیرد براساس تایم هست مثلا شما میگید ۵ ثانیه بعد از زمان الان درخواست را لغو کند در صورتیکه withTimeout مدت زمان میگیرد که درخواست ۵ ثانیه مهلت دارد کارش را اتمام کند.
تابع WithDeadline تا حدی شبیه به WithTimeout است اما با این تفاوت که پارامتر زمانی که میگیرد از نوع time.Time است و مدت زمانی که میگیرد براساس تایم هست مثلا شما میگید ۵ ثانیه بعد از زمان الان درخواست را لغو کند در صورتیکه withTimeout مدت زمان میگیرد که درخواست ۵ ثانیه مهلت دارد کارش را انجام دهد.

```go
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
Expand Down Expand Up @@ -409,8 +409,8 @@ context deadline exceeded
## 3.8.8 نکات کاربردی

1. هیچوقت سعی نکنید اینترفیس context را داخل یک ساختار ذخیره کنید اما می توانید embed کنید.
2. همیشه context باید بین لایه های خود منتقل کنید تا بتوانید کنترل بهتری برروی درخواست ها داشته باشید.
2. همیشه context باید بین لایههای خود منتقل کنید تا بتوانید کنترل بهتری برروی درخواست ها داشته باشید.
3. همیشه سعی کنید context را به عنوان اولین پارامتر توابع قرار دهید.
4. نام context به عنوان پارامتر توابع بهتر است ctx یا c باشد.
5. اگر هنوز مطمئن نیستید که با context چکاری میخواهید انجام دهید بهتر است context را با context.ToDo ایجاد کنید.
6. توجه کنید فقط تابعی که context والد را ایجاد کرده می تواند درخواست را لغو کند پس سعی نکنید تابع cancelFunc را به توابع زیرین پاس دهید.
6. توجه کنید فقط تابعی که context والد را ایجاد کرده می تواند درخواست را لغو کند پس سعی نکنید تابع cancelFunc را به توابع زیرین پاس دهید.
Loading
Loading