Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
黄成意
/
go_sku_server
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
3a6792ae
authored
Nov 03, 2025
by
hcy
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
并发问题
parent
32b298ac
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
111 additions
and
111 deletions
controller/sku_controller.go
model/prev_sku.go
service/service_ly.go
service/service_sample.go
service/service_spu.go
controller/sku_controller.go
View file @
3a6792ae
...
...
@@ -3,10 +3,13 @@ package controller
import
(
"context"
"encoding/json"
"fmt"
"github.com/tidwall/gjson"
"go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/
logger
"
"go_sku_server/pkg/
mongo
"
"go_sku_server/service"
"gopkg.in/mgo.v2/bson"
"sync"
"time"
...
...
@@ -41,14 +44,11 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
// 1. 提前提取所有请求参数(在主协程中,避免在子协程中访问 gin.Context)
requestParams
:=
service
.
ExtractRequestParams
(
ctx
)
// 2. 创建带超时的 context,用于控制所有协程的生命周期
// 5秒超时后,所有子协程都会收到取消信号
ctxWithTimeout
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
defer
cancel
()
// 确保函数返回时取消所有协程,释放资源
//抽取自营 或者联营 goods_id
zyService
:=
service
.
ZiyingService
{}
//实例化自营查询
lyService
:=
service
.
LyService
{}
//实例化联营查询
SpuService
:=
service
.
SpuService
{}
var
goodsIdArr
[]
string
if
GoodsIdStr
==
""
{
goodsIdMap
:=
ctx
.
PostFormMap
(
"goods_id"
)
...
...
@@ -63,11 +63,64 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
return
nil
}
//////////初始化公共变量 以及 批量查询///////////
zyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
lyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
for
_
,
goodsId
:=
range
goodsIdArr
{
if
len
(
goodsId
)
<
19
{
//自营
zyGoodsId
=
append
(
zyGoodsId
,
goodsId
)
}
else
{
//联营
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
}
}
//批量查询redis-sku信息
redisLySkuArr
:=
gredis
.
Hmget
(
"default_r"
,
"sku"
,
lyGoodsId
)
//批量查询归档的sku
preSkuIds
:=
make
([]
int64
,
0
)
for
_
,
goodsId
:=
range
goodsIdArr
{
if
redisLySkuArr
[
goodsId
]
==
""
{
preSkuIds
=
append
(
preSkuIds
,
gconv
.
Int64
(
goodsId
))
}
}
if
len
(
preSkuIds
)
>
0
{
var
prevSkuArr
[]
bson
.
M
prevSkuMongo
:=
mongo
.
Conn
(
"pre_sku"
)
query
:=
bson
.
M
{
"sku_id"
:
bson
.
M
{
"$in"
:
preSkuIds
,
},
}
err
:=
prevSkuMongo
.
DB
(
"ichunt"
)
.
C
(
"prev_sku"
)
.
Find
(
query
)
.
All
(
&
prevSkuArr
)
if
err
!=
nil
{
fmt
.
Println
(
"查询失败: %v"
,
err
)
}
for
_
,
preSkuOne
:=
range
prevSkuArr
{
jsonBytes
,
err
:=
json
.
Marshal
(
preSkuOne
)
if
err
!=
nil
{
continue
}
preSkuOneStr
:=
string
(
jsonBytes
)
skuId
:=
gjson
.
Get
(
preSkuOneStr
,
"sku_id"
)
.
String
()
redisLySkuArr
[
skuId
]
=
preSkuOneStr
}
}
//查询spu信息
redisLySpuArr
:=
SpuService
.
GetSpuList
(
redisLySkuArr
)
SpuService
.
SetInit
()
//设置查询公共变量
/////////////////多线程///////////////////////////
var
wg
sync
.
WaitGroup
ch
:=
make
(
chan
sync
.
Map
,
50
)
//管道
wgMax
:=
3
//线程数量最多多少
wgcount
:=
0
//当前线程数
zyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
lyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
temp
:=
make
(
map
[
string
]
interface
{})
//最后输出计算结果
for
_
,
goodsId
:=
range
goodsIdArr
{
//if len(goodsIdArr) > 100 {
// common.Output(ctx, 1001, "查询型号ID不得超过100个", "")
...
...
@@ -90,87 +143,49 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
defer
wg
.
Done
()
zyService
.
ZyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
}(
ctx
WithTimeout
,
requestParams
,
idsToProcess
,
ch
)
}(
ctx
,
requestParams
,
idsToProcess
,
ch
)
zyGoodsId
=
zyGoodsId
[
:
0
]
}
}
else
{
//联营
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
if
len
(
lyGoodsId
)
>=
goodsSliceCount
{
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程1002:"
)
common
.
PrintDebugHtml
(
ctx
,
lyGoodsId
)
wg
.
Add
(
1
)
idsToProcess
:=
make
([]
string
,
len
(
lyGoodsId
))
copy
(
idsToProcess
,
lyGoodsId
)
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程:"
+
goodsId
)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
defer
wg
.
Done
()
lyService
.
LyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
}(
ctxWithTimeout
,
requestParams
,
idsToProcess
,
ch
)
lyGoodsId
=
lyGoodsId
[
:
0
]
//单个sku详情
if
_
,
ok
:=
redisLySkuArr
[
goodsId
];
!
ok
{
temp
[
goodsId
]
=
false
continue
}
skuStr
:=
redisLySkuArr
[
goodsId
]
spuId
:=
gjson
.
Get
(
skuStr
,
"spu_id"
)
.
String
()
if
_
,
ok
:=
redisLySpuArr
[
spuId
];
!
ok
{
temp
[
goodsId
]
=
false
continue
}
}
}
if
len
(
zyGoodsId
)
>
0
{
common
.
PrintDebugHtml
(
ctx
,
"zy增加协程1003:"
)
common
.
PrintDebugHtml
(
ctx
,
zyGoodsId
)
wg
.
Add
(
1
)
//协程计数一
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
skuStr
,
goodsId
,
spuStr
string
,
ch
chan
sync
.
Map
)
{
defer
wg
.
Done
()
lyService
.
LyGoodsDetail
(
ctx
,
params
,
skuStr
,
goodsId
,
spuStr
,
ch
)
}(
ctx
,
requestParams
,
skuStr
,
goodsId
,
redisLySpuArr
[
spuId
],
ch
)
idsToProcess
:=
make
([]
string
,
len
(
zyGoodsId
)
)
copy
(
idsToProcess
,
zyGoodsId
)
wg
.
Add
(
1
)
wgcount
+=
1
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
defer
wg
.
Done
()
zyService
.
ZyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
}(
ctxWithTimeout
,
requestParams
,
idsToProcess
,
ch
)
if
wgcount
>=
wgMax
{
println
(
"线程数量:"
+
gconv
.
String
(
wgcount
))
wg
.
Wait
()
// 等待所有登记的goroutine都结束
wgcount
=
0
}
}
}
if
len
(
lyGoodsId
)
>
0
{
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程1004:"
)
common
.
PrintDebugHtml
(
ctx
,
lyGoodsId
)
wg
.
Add
(
1
)
idsToProcess
:=
make
([]
string
,
len
(
lyGoodsId
))
copy
(
idsToProcess
,
lyGoodsId
)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
defer
wg
.
Done
()
lyService
.
LyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
}(
ctxWithTimeout
,
requestParams
,
idsToProcess
,
ch
)
if
wgcount
>
0
{
//println("等待结束,现有运行线程数:" + gconv.String(wgcount))
//wg.Wait()
}
// 开启一个协程,等待所有任务完成,然后关闭channel
// 使用 context 来控制这个等待协程的生命周期
go
func
()
{
// 创建一个 done channel 用于通知 wg.Wait() 完成
done
:=
make
(
chan
struct
{})
go
func
()
{
wg
.
Wait
()
close
(
done
)
}()
// 等待 wg.Wait() 完成或 context 取消
select
{
case
<-
done
:
// 所有协程都正常完成
close
(
ch
)
case
<-
ctxWithTimeout
.
Done
()
:
// context 超时,不再等待剩余协程
// 等待一小段时间让协程有机会退出
time
.
Sleep
(
300
*
time
.
Millisecond
)
close
(
ch
)
logger
.
Log
(
"等待协程完成超时,强制关闭channel"
,
"sku"
,
1
)
}
}()
close
(
ch
)
//异步map最后转成map
temp
:=
make
(
map
[
string
]
interface
{})
for
{
select
{
case
GoodsRes
,
ok
:=
<-
ch
:
...
...
@@ -182,36 +197,12 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
temp
[
s
]
=
v
return
true
})
case
<-
ctxWithTimeout
.
Done
()
:
// context 超时或被取消
logger
.
Log
(
"协程整体处理超时,所有子协程已收到取消信号"
,
"sku"
,
1
)
// 继续从 channel 读取已经发送的数据,避免协程阻塞
// 等待 channel 被关闭(由上面的 wg.Wait() 协程关闭)
cleanupTimeout
:=
time
.
After
(
500
*
time
.
Millisecond
)
for
{
select
{
case
GoodsRes
,
ok
:=
<-
ch
:
if
!
ok
{
// channel 已关闭,所有协程都已退出
logger
.
Log
(
"channel已关闭,返回结果"
,
"sku"
,
1
)
return
temp
}
// 收集已经发送的数据
GoodsRes
.
Range
(
func
(
k
,
v
interface
{})
bool
{
s
,
_
:=
k
.
(
string
)
temp
[
s
]
=
v
return
true
})
case
<-
cleanupTimeout
:
// 清理超时,强制返回
logger
.
Log
(
"清理超时,强制返回"
,
"sku"
,
1
)
return
temp
}
}
case
<-
time
.
After
(
20
*
time
.
Second
)
:
println
(
"协程超时20秒"
)
return
temp
}
}
}
func
Synchronization
(
ctx
*
gin
.
Context
)
{
...
...
model/prev_sku.go
View file @
3a6792ae
...
...
@@ -7,5 +7,5 @@ type PrevSku struct {
ID
bson
.
ObjectId
`bson:"_id"`
SkuId
int64
`bson:"sku_id"`
SpuId
int64
`bson:"spu_id"`
SupplierId
int
64
`bson:"supplier_id"`
SupplierId
int
32
`bson:"supplier_id"`
}
service/service_ly.go
View file @
3a6792ae
This diff is collapsed.
Click to expand it.
service/service_sample.go
View file @
3a6792ae
...
...
@@ -83,9 +83,9 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
//抽取自营 或者联营 goods_id
zyService
:=
ZiyingService
{}
//实例化自营查询
lyService
:=
LyService
{}
//实例化联营查询
ch
:=
make
(
chan
sync
.
Map
)
//管道
p
:=
0
//总共协程
//
lyService := LyService{} //实例化联营查询
ch
:=
make
(
chan
sync
.
Map
)
//管道
p
:=
0
//总共协程
zyGoodsId
:=
make
([]
string
,
0
)
lyGoodsId
:=
make
([]
string
,
0
)
for
_
,
goodsId
:=
range
goodsIds
{
...
...
@@ -102,7 +102,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
}
else
{
//联营
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
if
len
(
lyGoodsId
)
>=
10
{
go
lyService
.
LyGoodsDetail
(
ctxWithTimeout
,
params
,
lyGoodsId
,
ch
)
//
go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
lyGoodsId
=
lyGoodsId
[
:
0
:
0
]
p
++
}
...
...
@@ -113,7 +113,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
p
++
}
if
len
(
lyGoodsId
)
>
0
{
go
lyService
.
LyGoodsDetail
(
ctxWithTimeout
,
params
,
lyGoodsId
,
ch
)
//
go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
p
++
}
//异步map最后转成map
...
...
service/service_spu.go
View file @
3a6792ae
package
service
import
(
"github.com/gomodule/redigo/redis"
"github.com/tidwall/gjson"
"go_sku_server/pkg/gredis"
)
type
SpuService
struct
{
var
UsdRate
float64
//美金匯率
type
SpuService
struct
{
}
func
(
ss
*
SpuService
)
g
etSpuList
(
skuArr
map
[
string
]
string
)
(
spuList
map
[
string
]
string
)
{
func
(
ss
*
SpuService
)
G
etSpuList
(
skuArr
map
[
string
]
string
)
(
spuList
map
[
string
]
string
)
{
var
spuIds
[]
string
for
_
,
skuStr
:=
range
skuArr
{
spuId
:=
gjson
.
Get
(
skuStr
,
"spu_id"
)
.
String
()
...
...
@@ -19,3 +21,10 @@ func (ss *SpuService) getSpuList(skuArr map[string]string) (spuList map[string]s
spuList
=
gredis
.
Hmget
(
"spu"
,
"spu"
,
spuIds
)
return
}
// 设置查询公共变量
func
(
ss
*
SpuService
)
SetInit
()
{
redisCon
:=
gredis
.
Conn
(
"default_r"
)
usdRatio
,
_
:=
redis
.
Float64
(
redisCon
.
Do
(
"HGET"
,
"erp_rate"
,
2
))
UsdRate
=
usdRatio
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment