Golang如何加速脚本执行效率
Golang如何加速脚本执行效率 你好,我是Go语言新手,今天刚加入这个论坛。
我正在编写一个TCP扫描器,想知道有没有什么方法能大幅提升脚本的运行速度?
现在它运行得太慢了。
以下是我的脚本:
func main() {
var hostName string
var concurrency int
logo()
flag.StringVar(&hostName, "i" , "" , "Run with your hostname or IP")
flag.IntVar(&concurrency , "c" , 50 , "Set the concurrency for greater speed")
flag.Parse()
var wg sync.WaitGroup
for i:=0; i<= concurrency; i++ {
wg.Add(1)
go func () {
Fullscan(hostName)
wg.Done()
}()
wg.Wait()
}
}
func Fullscan(hostName string) {
for i := 1; i <= 65535; i++ {
address := hostName + ":" + strconv.Itoa(i)
conn, err := net.DialTimeout("tcp" , address , 60*time.Second)
if err == nil {
fmt.Println("Port" , strconv.Itoa(i)+"/open")
conn.Close()
}
}
}
更多关于Golang如何加速脚本执行效率的实战教程也可以访问 https://www.itying.com/category-94-b0.html
天哪,这在我的机器上运行得非常好,感谢你的帮助!
更多关于Golang如何加速脚本执行效率的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
哎呀,我想我明白了。谢谢。
关于工作线程,具体是什么让你感到困惑?
我会测试一下。感谢你的帮助!我正在考虑在我的VPS上运行。
我以前没有这样做过,我只是全部使用 Go 协程来写,感谢你的建议。我会尝试一下。
你好,感谢你的建议。我会尝试并研究一下,但我对工作线程(workers)有点困惑,因为我是Go语言的新手。
我刚刚意识到,你目前甚至没有为每个主机启动一个 goroutine,而是启动了 concurrency 个 goroutine,每个 goroutine 都在对同一个主机进行完整的扫描。
与其为每个主机分配一个单独的 Go 协程,不如进一步拆分。创建 10、20、40 或任意数量的“工作者”,并通过通道从主循环向它们发送作业项。该作业项应包含要扫描的主机和端口。
func main() {
fmt.Println("hello world")
}
以下代码在我的机器上运行大约需要5秒:
package main
import (
"flag"
"fmt"
"net"
"os"
"time"
)
type portResult struct {
port int
open bool
}
func main() {
var hostName string
var concurrency int
flag.StringVar(&hostName, "i", "", "Give hostname or IP")
flag.IntVar(&concurrency, "c", 10, "set number of concurrent scans")
flag.Parse()
var chIn chan int = make(chan int)
var chOut chan portResult = make(chan portResult)
for i := 0; i < concurrency; i++ {
go runner(i, hostName, chIn, chOut)
}
go func() {
for p := 1; p <= 0xffff; p++ {
chIn <- p
}
}()
for r := 1; r <= 0xffff; r++ {
info := <-chOut
if info.open {
fmt.Printf("Port %v is open\n", info.port)
}
}
close(chIn)
close(chOut)
}
func runner(id int, host string, ports <-chan int, results chan<- portResult) {
for p := range ports {
fmt.Fprintf(os.Stderr, "%d: scanning port %v\n", id, p)
address := fmt.Sprintf("%s:%d", host, p)
conn, err := net.DialTimeout("tcp", address, time.Minute)
if err != nil {
results <- portResult{
port: p,
open: false,
}
continue
}
results <- portResult{
port: p,
open: true,
}
conn.Close()
}
}
$ time go run . -i localhost -c 100 | tee ports.txt
[…]
go run . -i localhost -c 100 4.81s user 5.32s system 269% cpu 3.755 total
tee ports.txt 0.00s user 0.00s system 0% cpu 3.755 total
结果向 stdout 打印了24行,这与我机器上运行并绑定到环回接口的服务数量相符。
另外请注意,在我的机器上,并发数超过4之后,速度没有明显提升。对于并发数4、5、10和100,实际耗时都在4.5到5秒之间。
你的代码存在几个关键问题导致扫描速度慢:
- 并发控制错误:
wg.Wait()在循环内部调用,导致实际是串行执行 - 端口扫描逻辑:每个goroutine都扫描全部65535个端口,造成重复工作
- 超时时间过长:60秒超时对于端口扫描来说太长了
以下是优化后的代码:
func main() {
var hostName string
var concurrency int
flag.StringVar(&hostName, "i", "", "Run with your hostname or IP")
flag.IntVar(&concurrency, "c", 50, "Set the concurrency for greater speed")
flag.Parse()
if hostName == "" {
fmt.Println("Please specify a host with -i flag")
return
}
ports := make(chan int, 100)
var wg sync.WaitGroup
// 启动worker goroutines
for i := 0; i < concurrency; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for port := range ports {
scanPort(hostName, port)
}
}()
}
// 发送端口到channel
for port := 1; port <= 65535; port++ {
ports <- port
}
close(ports)
wg.Wait()
}
func scanPort(host string, port int) {
address := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", address, 2*time.Second)
if err != nil {
return
}
conn.Close()
fmt.Printf("Port %d/open\n", port)
}
进一步优化可以使用更短的超时时间和连接复用:
func scanPortWithContext(host string, port int) {
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
var d net.Dialer
conn, err := d.DialContext(ctx, "tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return
}
conn.Close()
fmt.Printf("Port %d/open\n", port)
}
使用sync.Pool重用连接:
var dialerPool = sync.Pool{
New: func() interface{} {
return &net.Dialer{
Timeout: 500 * time.Millisecond,
}
},
}
func scanPortWithPool(host string, port int) {
dialer := dialerPool.Get().(*net.Dialer)
defer dialerPool.Put(dialer)
conn, err := dialer.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return
}
conn.Close()
fmt.Printf("Port %d/open\n", port)
}
这些优化将显著提升扫描速度:
- 真正的并发执行
- 每个端口只扫描一次
- 更合理的超时时间(500ms-2s)
- 避免资源重复创建

