苹果id切换外区
环境:mac、苹果账号
步骤一:在appstore账号设置
步骤二:切换地区
我选的澳门
步骤三:支付设置选择无
填写街道、电话,自行google,电话可以搜澳门电话生成器。
环境:mac、苹果账号
步骤一:在appstore账号设置
步骤二:切换地区
我选的澳门
步骤三:支付设置选择无
填写街道、电话,自行google,电话可以搜澳门电话生成器。
题目:一个goroutine打印0-100,一个goroutine打印a-z,两个goroutine交替打印。
考点:用channel通知另一个goroutine,并且不能出现goroutine阻塞。
核心原理:channel 是同步阻塞的
在没有缓冲的 channel(或容量已满的 channel)中:
发送方(chan <- val)会阻塞,直到有接收方准备好读取。
接收方(<-chan)也会阻塞,直到有发送方发来数据。这种阻塞机制就可以天然地用于控制两个 goroutine 的执行顺序。
方案一:
两个channel,一个用来控制打印数字,一个用来控制打印字母,goroutine先接收channel再开始打印,如果没有接收到信号就会阻塞,打印完再作为发送方向对方的channel发送信号,并且第二个goroutine打印完就不要再向channel发送信号了,否则会死锁。因为第一个goroutine已经打印完,不会再接收channel,导致goroutine死锁。
func Printnumandstring() {
chNumber := make(chan struct{})
chStr := make(chan struct{})
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
i := 0
for i <= 100 {
<-chNumber
for j := 0; j < 4 && i <= 100; j++ {
println(i)
i++
}
chStr <- struct{}{}
}
}()
go func() {
defer wg.Done()
for i := 'a'; i <= 'z'; i++ {
<-chStr
println(string(i))
if i != 'z' {
chNumber <- struct{}{}
}
}
}()
chNumber <- struct{}{}
wg.Wait()
} ch := make(chan int, 10)
for i := 0; i <= 10; i++ {
ch <- i
}
go func() {
for v := range ch {
fmt.Println(v)
}
}()问这段代码运行结果。
这段代码大体可以分为两部分,主协程创建一个缓冲区大小为10的int类型的channel并且循环写入0-10共11个元素,子协程消费channel并打印。
对channel熟悉的人可能会发现,缓冲区大小小于写入元素个数,写完9后channel会阻塞主,10无法再写入。再往下执行可能就不确定了,感觉goroutine会打印0-9。恭喜你,已经踩到坑了。
这段代码的坑就在于goroutine执行在后面,当主协程向channel写满10个后就已经阻塞程序执行了,也就不会走到goroutine消费这一步骤,最终导致程序卡死,报出fatal错误:fatal error: all goroutines are asleep - deadlock!
场景1:实现并发调用多个方法,有一个返回结果就都返回
思路:可以使用 select 语句结合通道来等待多个 goroutine 返回结果,一旦有 goroutine 返回结果,就立即处理该结果并结束程序。
/**
* @desc
* @date 2025/4/19
* @user yangshuo
*/
package main
import (
"context"
"fmt"
"math/rand"
"sync"
"time"
)
func mysql(ctx context.Context, ch chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
d := time.Duration(rand.Intn(3)+1) * time.Second
t := time.NewTimer(d)
defer t.Stop()
select {
case <-ctx.Done():
return
case <-t.C:
}
select {
case <-ctx.Done():
return
case ch <- "mysql":
}
}
func redis(ctx context.Context, ch chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
d := time.Duration(rand.Intn(3)+1) * time.Second
t := time.NewTimer(d)
defer t.Stop()
select {
case <-ctx.Done():
return
case <-t.C:
}
select {
case <-ctx.Done():
return
case ch <- "redis":
}
}
func httpReq(ctx context.Context, ch chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
d := time.Duration(rand.Intn(3)+1) * time.Second
t := time.NewTimer(d)
defer t.Stop()
select {
case <-ctx.Done():
return
case <-t.C:
}
select {
case <-ctx.Done():
return
case ch <- "http":
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 缓冲=1,避免第一个发送方被无谓阻塞
resChan := make(chan string, 1)
var wg sync.WaitGroup
wg.Add(3)
go mysql(ctx, resChan, &wg)
go redis(ctx, resChan, &wg)
go httpReq(ctx, resChan, &wg)
// 只拿第一个结果就取消其他 goroutine
select {
case res := <-resChan:
fmt.Println(res)
cancel()
case <-time.After(5 * time.Second):
t.Fatal("timeout")
}
wg.Wait()
// 不需要关闭 resChan(这里多发送者、且我们拿到一个结果就结束)
}
场景2:实现并发调用多个校验方法,有一个成功就返回成功,所有方法都失败就返回失败。
思路:与场景1不同的是,失败情况需要等待所有goroutine都执行完。
/**
* @desc
* @date 2025/4/20
* @user yangshuo
*/
package main
import (
"fmt"
"math/rand"
"time"
)
func validateFunc1() bool {
// 模拟验证逻辑
// 设置随机种子
return false
rand.Seed(time.Now().UnixNano())
// 生成随机数(0 或 1)
randomNum := rand.Intn(2)
// 根据随机数返回 true 或 false
result := randomNum == 1
fmt.Println(result)
return result
}
func validateFunc2() bool {
return false
// 设置随机种子
rand.Seed(time.Now().UnixNano())
// 生成随机数(0 或 1)
randomNum := rand.Intn(2)
// 根据随机数返回 true 或 false
result := randomNum == 1
fmt.Println(result)
return result
}
func validateFunc3() bool {
return false
// 模拟验证逻辑
// 设置随机种子
rand.Seed(time.Now().UnixNano())
// 生成随机数(0 或 1)
randomNum := rand.Intn(2)
// 根据随机数返回 true 或 false
result := randomNum == 1
fmt.Println(result)
return result
}
func main() {
// 定义验证函数
validateFuncs := []func() bool{validateFunc1, validateFunc2, validateFunc3}
// 使用 channel 通知是否有函数通过验证
passed := make(chan bool)
// 并发调用验证函数
for _, vf := range validateFuncs {
go func(fn func() bool) {
if fn() {
passed <- true
}
}(vf)
}
// 检查是否有函数通过验证
for range validateFuncs {
select {
case <-passed:
fmt.Println("Validation passed")
return
}
fmt.Println("Validation failed")
}
需要注意的是:当所有 goroutines 都未通过验证时,由于没有 goroutine 向 passed 通道发送消息,select 语句会一直阻塞等待消息,从而导致程序发生死锁。为了避免这种情况,可以加上default分支。
// 检查是否有函数通过验证
for range validateFuncs {
select {
case <-passed:
fmt.Println("Validation passed")
return
default:
}
} 实例代码
func doPatch(
ctx *gin.Context,
addrs []string,
request *graph_raw.SmartAmountListReq, txnCnt, rival *int64, level uint, sTime int64) ([]graph_raw.CapitalAddressEdge, error) {
wg := &sync.WaitGroup{}
mutex := sync.Mutex{}
res := make([]graph_raw.CapitalAddressEdge, 0)
limit := make(chan bool, 5)
for i := 0; i < len(addrs); i += 800 {
wg.Add(1)
start := i
go func() {
defer wg.Done()
limit <- true
group := collections.SliceSubRange(addrs, start, 800)
edgeList, _ := multiGetAddressData(ctx, group, request)
<-limit
mutex.Lock()
defer mutex.Unlock()
for _, v := range edgeList {
*txnCnt += int64(v.Count)
}
*rival += int64(len(edgeList))
slog.Infof(ctx, "req_level: %d, curr_level: %d, txnCnt : %d, rival: %d, stime: %d ", request.Level, level, *txnCnt, *rival, sTime)
res = append(res, edgeList...)
}()
cTime := time.Now().Unix()
timeout := int64(9 * 60)
totalTime := cTime - sTime
slog.Infof(ctx, "curr_time: %d, s_time: %d, total_time: %d", cTime, sTime, totalTime)
if totalTime >= timeout {
return res, serror.CustomErr("查询超时", serror.CustomErrCode)
}
}
wg.Wait()
return res, nil
}这段代码使用gorouting、waitgroup、sync.Mutex、channel,来实现并发下安全控制,
func doPatch(
ctx *gin.Context,
addrs []string,
request *graph_raw.SmartAmountListReq, txnCnt, rival *int64, level uint, sTime int64) ([]graph_raw.CapitalAddressEdge, error) {
wg := &sync.WaitGroup{}
mutex := sync.Mutex{}
res := make([]graph_raw.CapitalAddressEdge, 0)
limit := make(chan bool, 5)
timeout := int64(9 * 60)
var err error
for i := 0; i < len(addrs); i += 800 {
wg.Add(1)
start := i
go func(start int) {
defer wg.Done()
limit <- true
if _, ok := ctx.Get("request_canceled"); ok {
slog.Infof(ctx, "request_canceled: %v", request)
err = serror.CustomErr("查询取消", serror.CustomErrCode)
return
}
cTime := time.Now().Unix()
totalTime := cTime - sTime
slog.Infof(ctx, "curr_time: %d, s_time: %d, total_time: %d, i: %d, level: %d", cTime, sTime, totalTime, start, level)
if totalTime >= timeout {
slog.Warnf(ctx, "smart超时: %v, curr_time: %d, s_time: %d, total_time: %d, i: %d, level: %d, req_level: %d, txnCnt : %d, rival: %d", request.Address, cTime, sTime, totalTime, start, level, request.Level, *txnCnt, *rival)
err = serror.CustomErr("查询超时", serror.CustomErrCode)
return
}
group := collections.SliceSubRange(addrs, start, 800)
edgeList, _ := multiGetAddressData(ctx, group, request)
<-limit
mutex.Lock()
defer mutex.Unlock()
for _, v := range edgeList {
*txnCnt += int64(v.Count)
}
*rival += int64(len(edgeList))
slog.Infof(ctx, "req_level: %d, curr_level: %d, txnCnt : %d, rival: %d, stime: %d ", request.Level, level, *txnCnt, *rival, sTime)
res = append(res, edgeList...)
}(start)
if err != nil {
return res, err
}
}
wg.Wait()
return res, err
} git merge --squash xxx合并并将所有提交放到暂存区,需手动提交,作用:将多个提交合为1个。
go build 是 Go 语言的一个编译打包工具,它可以将 Go 语言编写的源码文件编译并打包成一个可执行文件。
在执行 go build 的过程中,Go 编译器会进行几个步骤的操作:
解析源代码,生成 AST(抽象语法树)。
从 AST 生成 SSA(静态单分配)形式的字节码。
优化字节码。
生成机器代码,生成可执行文件。
如果你想在 go build 执行过程中进行某些操作,你可能需要使用 Go 的工具链,如 go/ast,go/token,go/parser,go/types 等包来操作 AST,或者使用 go/ssa 包来操作 SSA 形式的字节码。
在 Golang 中,可以使用各种方法来控制并发并限制 goroutine 的数量。以下是一种可能的实现方式,可以最多同时运行 50 个 goroutine:
package main
import (
"sync"
)
func main() {
maxConcurrency := 50
taskCount := 100
var wg sync.WaitGroup
semaphore := make(chan struct{}, maxConcurrency)
for i := 0; i < taskCount; i++ {
wg.Add(1)
go func(taskID int) {
semaphore <- struct{}{} // 占用一个信号量,限制并发数量
// 执行你的任务代码
// ...
<-semaphore // 释放信号量
wg.Done()
}(i)
}
wg.Wait()
}在上面的示例中,使用了一个 sync.WaitGroup 来等待所有任务完成。通过创建一个有容量的 chan struct{},我们可以使用带缓冲的通道作为信号量来控制 goroutine 的数量。maxConcurrency 变量定义了最大并发数量。
在每个 goroutine 中,首先会占用一个信号量(通过将空结构体写入通道),这将限制并发数量。然后在任务完成后释放信号量(通过从通道读取一个值)。sync.WaitGroup 用于等待所有任务完成。
请注意,这只是一种示例实现方式,您可以根据实际需求和情况进行适当的调整和修改。确保在使用并发控制时遵循最佳实践,以避免竞态条件和其他并发问题。
Q1: elasticsearch不能以root身份启动
Q2:
[2023-11-14T11:34:19,978][WARN ][o.e.h.n.Netty4HttpServerTransport] [safeis-qitaihe-test] received plaintext http traffic on an https channel, closing connection Netty4HttpChannel{localAddress=/127.0.0.1:9200, remoteAddress=/127.0.0.1:33384}
解决方法:
es/config/es.yml
xpack.security.enabled: true => xpack.security.enabled: false
require: 必传
oneof: "oneof=left right",其中一个。
min:验证数值类型或字符串类型的值是否大于等于指定的最小值;
max:验证数值类型或字符串类型的值是否小于等于指定的最大值;
eq:验证两个值是否相等;
ne:验证两个值是否不相等;
len:验证字符串、数组或切片的长度是否等于指定的长度;
regex:验证字符串是否匹配指定的正则表达式;
email:验证字符串是否为有效的电子邮件地址;
url:验证字符串是否为有效的 URL 地址;
numeric:验证字符串是否只包含数字字符;
alpha:验证字符串是否只包含字母字符;
alphanum:验证字符串是否只包含字母和数字字符;
ascii:验证字符串是否只包含 ASCII 字符;
base64:验证字符串是否为有效的 Base64 编码;
file:验证上传的文件是否符合要求,例如文件类型、大小等。