gpt4 book ai didi

go - 将一个 slice 分成N个 slice

转载 作者:行者123 更新时间:2023-12-03 10:07:38 29 4
gpt4 key购买 nike

我正在尝试实现一个将 TCP 端口 slice 拆分为 x 个其他 slice 的功能。这些 slice 将发送给将扫描这些端口的工作人员,因此 x 由工作人员的数量设置。
这是代码:

// createJobs split portsToScan from a specified protocol into an equal number
// of jobs that will be returned.
func (t *Target) createJobs(proto string) ([]jobMsg, error) {
// init jobs slice
jobs := []jobMsg{}

// check protocol accordance
if _, ok := t.portsToScan[proto]; !ok {
return nil, fmt.Errorf("no such protocol %q in current protocol list", proto)
}

// if proto is ICMP, we do not need to scan ports
if proto == "icmp" {
return []jobMsg{
jobMsg{ip: t.ip, protocol: proto},
}, nil
}

step := (len(t.portsToScan[proto]) + t.workers - 1) / t.workers

for i := 0; i < len(t.portsToScan[proto]); i += step {
batch := t.portsToScan[proto][i:min(i+step, len(t.portsToScan[proto]))]

jobs = append(jobs, jobMsg{
ip: t.ip,
protocol: proto,
ports: batch,
})
}

return jobs, nil
}
这是相应的单元测试:
func TestTarget_createJobs(t *testing.T) {
tests := []struct {
name string
pts map[string][]string
workersCount int
wantErr bool
}{
{
name: "5-1",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 1,
},
{
name: "5-2",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 2,
},
{
name: "5-3",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 3,
},
{
name: "5-4",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 4,
},
{
name: "5-5",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 5,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tg := &Target{
portsToScan: tt.pts,
workers: tt.workersCount,
}
got, err := tg.createJobs("tcp")
if (err != nil) != tt.wantErr {
t.Errorf("Target.createJobs() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(got) != tt.workersCount {
t.Errorf("Target.createJobs() = %d, wanted %d jobs; joblist %v", len(got), tt.workersCount, got)
}
})
}
}


func min(a, b int) int {
if a <= b {
return a
}
return b
}
测试的输出给了我这个结果:
--- FAIL: TestTarget_createJobs/5-4 (0.00s)
scan_test.go:309: Target.createJobs() = 3, wanted 4 jobs; joblist [{ 0 tcp [1 2]} { 0 tcp [3 4]} { 0 tcp [5]}]
初始端口列表保存在 t.portsToScan[proto] 中和 worker 的数量(所以我想创建的 slice 数量)由 t.workers 设置.
最后, len(jobs)必须等于 t.workers但我找不到怎么做。

最佳答案

您的算法使用 step作为批次的大小:

step := (len(t.portsToScan[proto]) + t.workers - 1) / t.workers
这不是最佳尺寸。例如,如果您有 4 个要扫描的端口和 3 个工作程序,这将导致 step = 2 ,这意味着您将只有 2 个工作 ( 2+2=4 )。但是最好(更优化)有 3 个批次(尺寸为 2+1+1=4 )。
所以批次的大小应该是
defSize := len(t.portsToScan[proto]) / t.workers
问题在于,如果长度不是 t.workers 的倍数,一些最后的元素(端口)将不会分配给任何作业。使用 defSize+1因为所有的工作都太多了。
所以最佳解决方案是在“中间”:一些工作会有 defSize要扫描的端口,有些会有 defSize+1 .多少必须有 defSize+1 ?如果所有的人都有的话,就和失踪一样多 defSize :
numBigger := len(t.portsToScan[proto]) - defSize*t.workers
请注意,如果要扫描的端口数少于工作程序,则上述计算产生 defSize=0 ,所以一些 worker 会得到 0要扫描的端口,有些会得到 1 .没关系,但是您不应该使用 0 添加作业要扫描的端口。
使用此分布:
defSize := len(t.portsToScan[proto]) / t.workers
numBigger := len(t.portsToScan[proto]) - defSize*t.workers

size := defSize+1
for i, idx := 0, 0; i < t.workers; i++ {
if i == numBigger {
size--
if size == 0 {
break // 0 ports left to scan
}
}
jobs = append(jobs, jobMsg{
ip: t.ip,
protocol: proto,
ports: t.portsToScan[proto][idx : idx+size],
})
idx += size
}

关于go - 将一个 slice 分成N个 slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64590042/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com