当前位置:网站首页>[golang] quick review guide quickreview (VIII) -- goroutine
[golang] quick review guide quickreview (VIII) -- goroutine
2022-06-23 20:04:00 【DDGarfield】
goroutine yes Golang specific , Similar to threads , But threads are scheduled and managed by the operating system , and goroutine By Golang User state threads that perform scheduling management at runtime .
1.C# Thread operation of
1.1 Create thread
static void Main(string[] args)
{
Thread thread = new Thread(Count);
thread.IsBackground = true;
thread.Start();
for (int i = 0; i < 10; i++)
Console.Write("x\n");
}
static void Count()
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i); ;
}
}
1.2 Pass parameters to thread
Thread The constructor has two parameters ParameterizedThreadStart And ThreadStart
public delegate void ParameterizedThreadStart(object? obj);
public delegate void ThreadStart();
you 're right , One is nonparametric delegation ,, One is a parameterized delegate and the parameter type is object, Therefore, the method parameter we use to create the thread needs to be object type , And then inside the object Type parameters are converted :
static void Main(string[] args)
{
Thread thread = new Thread(Count);
thread.IsBackground = true;
thread.Start(100);
for (int i = 0; i < 10; i++)
Console.Write("x\n");
}
static void Count(object times)
{
int count = (int)times;
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i); ;
}
}
Of course The most simple Or use it directly lambda expression
static void Main(string[] args)
{
Thread thread = new Thread(()=>{
Count(100);
});
thread.IsBackground = true;
thread.Start();
for (int i = 0; i < 10; i++)
Console.Write("x\n");
}
static void Count(object times)
{
int count = (int)times;
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i); ;
}
}
Be careful : Use Lambda The expression can be simply given to Thread Pass parameters , But after the thread starts , You may accidentally modify the captured variables , This needs more attention . For example, in the loop body , It is best to create a temporary variable .
1.3 Thread safety and locking
Look at thread safety from the singleton mode :
class Student
{
private static Student _instance =new Student();
private Student()
{
}
static Student GetInstance()
{
return _instance;
}
}
** The singleton pattern , Our intention is to always keep the class instantiated once and then ensure that there is only one instance in memory .** In the above code, when the class is loaded , Complete the initialization of static private variables , Whether it's needed or not , Will be instantiated , This is called
Single case mode of hungry man mode. Although there is no thread safety problem , But if this class does not use , There is no need to instantiate . Then we have the following expression : When needed , Just instantiate
class Student
{
private static Student _instance;
private Student()
{
}
static Student GetInstance()
{
if (_instance == null)
_instance = new Student();
return _instance;
}
}
The above code , Judge whether the static private variable is empty when calling , And then assign a value . In fact, there is a thread safety problem : Multithreaded call GetInstance(), When multiple threads execute at the same time , Conditions _instance == null May be satisfied at the same time . such _instance This completes multiple instantiation assignment operations , It leads to our lock Lock
private static Student _instance;
private static readonly object locker = new object();
private Student()
{
}
static Student GetInstance()
{
lock (locker)
{
if (_instance == null)
_instance = new Student();
}
return _instance;
}
- The first thread runs , It will be locked
Lock - The second thread runs , First detected locker The object is " Lock " state ( Whether there are threads in
lockInside , Not done ), The thread will block waiting for the first thread to unlock - The first thread is finished
lockBody code , Unlock , The second thread will continue to execute
It seems to be perfect , But in the case of multithreading , Every time I have to go through , testing ( Is it blocked ), locked , Unlock , In fact, it affects the performance , Our original goal was to return a single instance .** We are testing locker Before the object is locked , If the instance already exists , Then the follow-up work is unnecessary .** So there's the following Double check :
private static Student _instance;
private static readonly object locker = new object();
private Student()
{
}
static Student GetInstance()
{
if (_instance == null)
{
lock (locker)
{
if (_instance == null)
_instance = new Student();
}
}
return _instance;
}
1.4 Task
Threads have two types of work :
- CPU-Bound: Computationally intensive , Spend most of your time executing CPU Operation of intensive work , This type of work never leaves a thread waiting .
- IO-Bound:I/O intensive , The act of spending most of your time waiting for something to happen , I've been waiting , The type of work that causes the thread to enter the waiting state . Such as through http Request access to resources .
about IO-Bound The operation of , Time is spent mainly on I/O On , And in the CPU It takes almost no time . For this , More recommended Task Write asynchronous code , And for CPU-Bound and IO-Bound Asynchronous code is not the focus of this article , The blogger will give an overview of Task The advantages of :
- Stop waiting :: With
HttpClientUse asynchronous code to requestGetStringAsyncFor example , This is obviously aI/O-Bound, Finally, the local network library of the operating system will be called , System API call , For example, the person who initiated the request socket, But the length of time is not determined by the code , It depends on the hardware , operating system , Network situation . Control is returned to the caller , We can do other things , This allows the system to handle more work instead of waiting I/O End of call . untilawaitTo get the result of the request . - Let the caller stop waiting : about
CPU-Bound, There is no way to avoid using a thread for computation , Because this is a computing intensive job after all . But useTaskThe asynchronous code of (asyncAndawait) It can not only interact with background threads , You can also let the caller continue to respond ( Other operations can be performed concurrently ). ditto , Until I metawaitwhen , Asynchronous methods give way to callers .
2.Golang Of goroutine
2.1 start-up goroutine
Golang Start one in goroutine No, C# The thread of is so troublesome , Just add the keyword before the calling method go.
func main(){
go Count(100)
}
func Count(times int) {
for i := 0; i < times; i++ {
fmt.Printf("%v\n", i)
}
}
2.2 goroutine Synchronization of
stay C# The task (Task) have access to Task.WhenAll To wait for Task Object complete . And in the Golang It looks simple and rough , It will use sync Bag WaitGroup, Then make a register like a roster :
- start-up - Count +1
- completion of enforcement - Count -1
- complete
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func main() {
// Register
wg.Add(2)
go Count(100)
go Count(100)
// Waiting for all registered goroutine It's all over
wg.Wait()
fmt.Println(" Execution completed ")
}
func Count(times int) {
// Execution completed
defer wg.Done()
for i := 0; i < times; i++ {
fmt.Printf("%v\n", i)
}
}
2.3 channel passageway
One goroutine Send a specific value to another goroutine Our communication mechanism is channel
2.3.1 channel Statement
channel Is a reference type
var Variable chan Element type
chan Element type Follow struct,interface equally , Is a type . The following element types define the channel specific storage types .
2.3.2 channel initialization
After the statement channel It's a null value nil, Initialization is required to use .
var ch chan int
ch=make(chan int,5) //5 Buffer size set for , Optional parameters
2.3.3 channel operation
Operate the three board axe :
- send - send out
ch<-100
The arrow points from the value to the channel
- receive - receive
value:=<-ch
i, ok := <-ch1 // After the channel is closed, the value can be taken ok=false
// perhaps
for i := range ch1 { // When the channel is closed, it exits for range loop
fmt.Println(i)
}
The arrow points from the channel to the variable
- close - close
close(ch)
2.3.3 Buffered and unbuffered
ch1:=make(chan int,5) //5 Buffer size set for , Optional parameters
ch2:=make(chan int)
Unbuffered channels , Unbuffered channels can only send values when they receive them .
- Only pass values to the channel , Do not receive from channel , Will appear
deadlock - Receive only from the channel , Do not send to the channel , Blocking can also occur
The use of unbuffered channels for communication will result in the transmission and reception of goroutine Synchronization . therefore , Unbuffered channels are also called Synchronous channel .
There are buffered channels , It can effectively alleviate the embarrassment of unbuffered channels , But the passage is full , The above embarrassment still exists .
2.3.4 One way passage
Restrict channels to send or receive only in functions , One way passage make oneself up and go on the stage , The one-way channel is used in the parameters of the function , No new keywords have been introduced , Simply change the position of the arrow :
chan<- int Write but not read
<-chan int Read only don't write
Function transfer parameter and any assignment operation can A two-way channel is converted to a one-way channel , conversely , no way .
2.3.5 Multiplexing
package main
import "fmt"
func main() {
ch := make(chan int, 1)
for i := 0; i < 10; i++ {
select {
case x := <-ch:
fmt.Printf(" The first %v Time ,x := <-ch, Read the value from the channel %v", i+1, x)
fmt.Println()
case ch <- i:
fmt.Printf(" The first %v Time , perform ch<-i", i+1)
fmt.Println()
}
}
}
The first 1 Time , perform ch<-i
The first 2 Time ,x := <-ch, Read the value from the channel 0
The first 3 Time , perform ch<-i
The first 4 Time ,x := <-ch, Read the value from the channel 2
The first 5 Time , perform ch<-i
The first 6 Time ,x := <-ch, Read the value from the channel 4
The first 7 Time , perform ch<-i
The first 8 Time ,x := <-ch, Read the value from the channel 6
The first 9 Time , perform ch<-i
The first 10 Time ,x := <-ch, Read the value from the channel 8
Select The rules of multiplexing :
- Can handle one or more channel Sending of / Receive operation .
- If more than one
caseAt the same time satisfy ,selectWill randomly choose one . - For no
caseOfselect{}Will be waiting , It can be used to block main function .
2.5 Concurrent security and locking
goroutine It's through channel Channel for communication . No concurrency security issues . however , In fact, the operation of public resources cannot be completely avoided , If more than one goroutine Operate these public resources at the same time , Concurrency security issues may occur , Follow C# Same thread as , The emergence of locks is to solve this problem :
2.5.1 The mutex
The mutex , This is just like C# The mechanism of the lock is the same , One goroutine visit , The other can only wait for the release of the mutex . Also need to sync package :
sync.Mutex
var lock sync.Mutex
lock.Lock()// Lock
// Operate common resources
lock.Unlock()// Unlock
2.5.2 Read write mutex
A mutex is completely mutex , If you read more and write less , Most of the goroutine All reading , A small amount of goroutine Writing , There is no need to lock concurrent reads . When using , Still need sync package :
sync.RWMutex
There are two types of read-write locks :
- Read the lock
- Write lock
import (
"fmt"
"sync"
)
var (
lock sync.Mutex
rwlock sync.RWMutex
)
rwlock.Lock() // Add write lock
// The effect is equivalent to mutex
rwlock.Unlock() // Unlock the lock
rwlock.RLock() // Add read lock
// Can't read or write
rwlock.RUnlock() // Interpreting locks
2.6* sync.Once
goroutine We have used the synchronization of sync.WaitGroup
Add(count int)Counter accumulation , Calling goroutine External execution , Designated by the developer- Done() Counter -1, stay goroutine Internal implementation
- Wait() Blocking Until the counter is 0
And then there's another one sync.Once, seeing the name of a thing one thinks of its function , once , Only once .
func (o *Once) Do(f func()) {}
var handleOnce sync.Once
handleOnce.Do( function )
sync.Once In fact, it contains a mutex and a Boolean value , Mutexes guarantee the security of Boolean values and data , and Boolean value Used to record whether initialization is completed . In this way, the design can ensure that the initialization operation is concurrent and safe , And initialization will not be performed more than once .
type Once struct {
// done indicates whether the action has been performed.
// It is first in the struct because it is used in the hot path.
// The hot path is inlined at every call site.
// Placing done first allows more compact instructions on some architectures (amd64/x86),
// and fewer instructions (to calculate offset) on other architectures.
done uint32
m Mutex
}
2.7* sync.Map
Golang Of map It's not concurrent security .sync The package provides an out of the box version of concurrent security map–sync.Map.
Out of the box no need Like built-in map The use of make function initialization It can be used directly . meanwhile sync.Map Built in things like Store、Load、LoadOrStore、Delete、Range And so on .
var m = sync.Map{}
m.Store(" sichuan ", " Chengdu ")
m.Store(" Chengdu ", " High-tech zone ")
m.Store(" High-tech zone ", " Yinglong South 1st Road ")
m.Range(func(key interface{}, value interface{}) bool {
fmt.Printf("k=:%v,v:=%v\n", key, value)
return true
})
fmt.Println()
v, ok := m.Load(" Chengdu ")
if ok {
fmt.Println(v)
}
fmt.Println()
value, loaded := m.LoadOrStore(" shaanxi ", " Xi'an ")
fmt.Println(value)
fmt.Println(loaded)
m.Range(func(key interface{}, value interface{}) bool {
fmt.Printf("k=:%v,v:=%v\n", key, value)
return true
})
fmt.Println()
//【 Value taking and creation 】
// Load when it exists , Add... If it doesn't exist
value1, loaded1 := m.LoadOrStore(" sichuan ", " Chengdu ")
fmt.Println(value1)
fmt.Println(loaded1)
m.Range(func(key interface{}, value interface{}) bool {
fmt.Printf("k=:%v,v:=%v\n", key, value)
return true
})
fmt.Println()
//【 Delete 】
// Load and delete key There is
value2, loaded2 := m.LoadAndDelete(" sichuan ")
fmt.Println(value2)
fmt.Println(loaded2)
m.Range(func(key interface{}, value interface{}) bool {
fmt.Printf("k=:%v,v:=%v\n", key, value)
return true
})
fmt.Println()
// Load and delete key non-existent
value3, loaded3 := m.LoadAndDelete(" Beijing ")
fmt.Println(value3)
fmt.Println(loaded3)
m.Range(func(key interface{}, value interface{}) bool {
fmt.Printf("k=:%v,v:=%v\n", key, value)
return true
})
fmt.Println()
m.Delete(" Chengdu ") // The interior is called LoadAndDelete
//【 Traverse 】
m.Range(func(key interface{}, value interface{}) bool {
fmt.Printf("k=:%v,v:=%v\n", key, value)
return true
})
fmt.Println()
k=: sichuan ,v:= Chengdu
k=: Chengdu ,v:= High-tech zone
k=: High-tech zone ,v:= Yinglong South 1st Road
High-tech zone
Xi'an
false
k=: sichuan ,v:= Chengdu
k=: Chengdu ,v:= High-tech zone
k=: High-tech zone ,v:= Yinglong South 1st Road
k=: shaanxi ,v:= Xi'an
Chengdu
true
k=: sichuan ,v:= Chengdu
k=: Chengdu ,v:= High-tech zone
k=: High-tech zone ,v:= Yinglong South 1st Road
k=: shaanxi ,v:= Xi'an
Chengdu
true
k=: shaanxi ,v:= Xi'an
k=: Chengdu ,v:= High-tech zone
k=: High-tech zone ,v:= Yinglong South 1st Road
<nil>
false
k=: Chengdu ,v:= High-tech zone
k=: High-tech zone ,v:= Yinglong South 1st Road
k=: shaanxi ,v:= Xi'an
k=: High-tech zone ,v:= Yinglong South 1st Road
k=: shaanxi ,v:= Xi'an
2.8 The singleton pattern
Sum up ,sync.Once In fact, it contains a mutex and a Boolean value , This Boolean value is equivalent to C# The first judgment of double test in singleton mode . So in golang Available in sync.Once Implement singleton mode :
package singleton
import (
"sync"
)
type singleton struct {}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
2.9* Atomic manipulation
The lock operation in the code is time-consuming because it involves context switching in kernel state 、 The cost is relatively high . For basic data types, we can also use atomic operations to ensure concurrency security .Golang Atomic operations in are performed by the built-in standard library sync/atomic Provide . Because there are few scenes , No introduction , For detailed operation, please consult and learn by yourself .
边栏推荐
- 教你如何用网页开发桌面应用
- Is it safe to make new debt
- The "open source star picking program" container pulls private images from harbor, which is a necessary skill for cloud native advanced technology
- What conditions do you need to meet to fight new debts? Is it safe to fight new debts
- 【Golang】类型转换归纳总结
- 【Golang】深究字符串——从byte rune string到Unicode与UTF-8
- 深入理解和把握数字经济的基本特征
- 准备好迁移上云了?请收下这份迁移步骤清单
- 35岁危机?内卷成程序员代名词了…
- Deep learning of handlebar handwriting (15): building your own corpus on hugging face
猜你喜欢

Implementation of microblog system based on SSM

Live sharing | Tencent cloud mongodb intelligent diagnosis and Performance Optimization Practice

Can the biggest gamefi crash victim survive the bear market in May| May Monthly Report

如何通过7个步骤编写出色的在线用户手册

图扑软件数字孪生智慧水务,突破海绵城市发展困境

如何使用物联网低代码平台进行流程管理?

Syntaxe des requêtes fédérées SQL (inline, left, right, full)

Syntax of SQL union query (inline, left, right, and full)

Kubernetes 资源拓扑感知调度优化

Leaders of Hangcheng street, Bao'an District and their delegation visited lianchengfa for investigation
随机推荐
Naacl 2022 finds | byte proposes MTG: multilingual text generation data set
【Golang】快速复习指南QuickReview(十)——goroutine池
@@脚本实现Ishell自动部署
墨天轮访谈 | IvorySQL王志斌—IvorySQL,一个基于PostgreSQL的兼容Oracle的开源数据库
【Golang】快速复习指南QuickReview(四)——函数
Add two factor authentication, not afraid of password disclosure, let alone 123456
游戏资产复用:更快找到所需游戏资产的新方法
Gaussdb (DWS) database intelligent monitoring operation and maintenance service - node monitoring indicators
Live sharing | Tencent cloud mongodb intelligent diagnosis and Performance Optimization Practice
开源 SPL 重新定义 OLAP Server
Deeply understand and grasp the basic characteristics of digital economy
The golden nine silver ten, depends on this detail, the offer obtains the soft hand!
Can the biggest gamefi crash victim survive the bear market in May| May Monthly Report
Kubernetes 资源拓扑感知调度优化
Live broadcast review | detailed explanation of koordinator architecture of cloud native hybrid system (complete ppt attached)
GL Studio 5 installation and experience
想开个户,在股票网上开户安全吗?资金会被骗走吗?
盘点四种WiFi加密标准:WEP、WPA、WPA2、WPA3
金鱼哥RHCA回忆录:DO447管理用户和团队的访问--用团队有效地管理用户
Use of the vs2022scanf function. An error is reported when using scanf - the return value is ignored: Solutions