Golang与Python中的UDP性能差

Golang与Python中的UDP性能差,python,go,networking,udp,Python,Go,Networking,Udp,我想尽快发送尽可能多的UDP数据包。我尝试了在包中发送UDP数据的不同方法,但结果如下: func main() { for i := 0; i < THREADS; i++ { go loopSendHello() } // Sleep forever <-make(chan bool, 1) } func loopSendHello() { for { sendHello() } } func

我想尽快发送尽可能多的UDP数据包。我尝试了在包中发送UDP数据的不同方法,但结果如下:

func main() {
    for i := 0; i < THREADS; i++ {
        go loopSendHello()
    }

    // Sleep forever
    <-make(chan bool, 1)
}

func loopSendHello() {
    for {
        sendHello()
    }
}

func sendHello() {
    // Setup conn
    addr := net.UDPAddr{
        IP:   net.IP{192, 168, 1, xxx},
        Port: 1337,
    }
    conn, err := net.ListenPacket("udp", "")
    if err != nil {
        log.Fatal("Listen:", err)
    }

    n, err := conn.WriteTo([]byte("hello"), &addr)
    if err != nil {
        log.Fatal("Error while writing to conn! :", err)
    }

    conn.Close()
}
使用Wireshark的基准测试:。这是从1毫秒到大约10毫秒的延迟!疯狂的差异


如何才能在Go中达到python的速度?

因此我决定非常快速地创建一个简单的基准,在没有任何线程或糟糕编程技术的情况下发送200000个UDP数据包。基准测试介于Go和Python之间。此外,我希望基准测试尽可能快地进行协调。我曾使用C语言进行协调,但由于我使用的是Windows,所以似乎最容易使用Rust

防锈代码:

use std::time::{SystemTime};
use std::net::UdpSocket;

const DATA: &[u8] = &[0; 1024];

fn main() {
    let time_start = SystemTime::now();

    let socket = UdpSocket::bind("192.168.1.155:1339").unwrap();
    for _ in 0..200000 {
        socket.send_to(DATA, "192.168.1.122:80").unwrap();
    }
    let elapsed = time_start.elapsed().unwrap();
    println!("Time {} ms to send 200 000 packets", elapsed.as_millis());
}
平均结果(内置-释放模式):
发送200000个数据包需要1863毫秒的时间

对于Go基准测试,这基本上就是代码:

var buff = []byte("")

func main() {
    buff = []byte(RandomString(1024))

    conn, err := net.ListenUDP("udp", &net.UDPAddr{})
    if err != nil {
        log.Fatal("Listen:", err)
    }

    loopSendHello(*conn)
    conn.Close()
}

func loopSendHello(conn net.UDPConn) {
    timeStart := time.Now()
    for i:=0; i < 200000; i++ {
        sendHelloEdited(&conn)
    }
    timeStop := time.Now()
    timeDelta := timeStop.Sub(timeStart)
    fmt.Println("Took", timeDelta.Milliseconds(), "ms to send 200 000 packets.")
}

// targetAddr is target address in form of net.UDPAddr
func sendHelloEdited(conn *net.UDPConn) {
    _, err := conn.WriteToUDP(buff, &targetAddr)
    if err != nil {
        log.Fatal("Error while writing to conn! :", err)
    }
}
def main():
    x = 0
    data = random._urandom(1024)
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    addr = (str(ip), int(port))
    startTime = datetime.datetime.now()
    while x < 200000:
        s.sendto(data, addr)
        x += 1
    s.close()
    endTime = datetime.datetime.now()
    deltaTime = endTime - startTime
    print("Took", deltaTime, "to send 200 000 packets")

main()
有趣的是,python的结果总是很快,平均输出为:
需要0:00:01.831531才能发送200000个数据包


因此,Go看起来确实是最慢的,但只是稍微慢了一点。

因此我决定非常快速地创建一个简单的基准,在没有任何线程或糟糕编程技术的情况下发送200000个UDP数据包。基准测试介于Go和Python之间。此外,我希望基准测试尽可能快地进行协调。我曾使用C语言进行协调,但由于我使用的是Windows,所以似乎最容易使用Rust

防锈代码:

use std::time::{SystemTime};
use std::net::UdpSocket;

const DATA: &[u8] = &[0; 1024];

fn main() {
    let time_start = SystemTime::now();

    let socket = UdpSocket::bind("192.168.1.155:1339").unwrap();
    for _ in 0..200000 {
        socket.send_to(DATA, "192.168.1.122:80").unwrap();
    }
    let elapsed = time_start.elapsed().unwrap();
    println!("Time {} ms to send 200 000 packets", elapsed.as_millis());
}
平均结果(内置-释放模式):
发送200000个数据包需要1863毫秒的时间

对于Go基准测试,这基本上就是代码:

var buff = []byte("")

func main() {
    buff = []byte(RandomString(1024))

    conn, err := net.ListenUDP("udp", &net.UDPAddr{})
    if err != nil {
        log.Fatal("Listen:", err)
    }

    loopSendHello(*conn)
    conn.Close()
}

func loopSendHello(conn net.UDPConn) {
    timeStart := time.Now()
    for i:=0; i < 200000; i++ {
        sendHelloEdited(&conn)
    }
    timeStop := time.Now()
    timeDelta := timeStop.Sub(timeStart)
    fmt.Println("Took", timeDelta.Milliseconds(), "ms to send 200 000 packets.")
}

// targetAddr is target address in form of net.UDPAddr
func sendHelloEdited(conn *net.UDPConn) {
    _, err := conn.WriteToUDP(buff, &targetAddr)
    if err != nil {
        log.Fatal("Error while writing to conn! :", err)
    }
}
def main():
    x = 0
    data = random._urandom(1024)
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    addr = (str(ip), int(port))
    startTime = datetime.datetime.now()
    while x < 200000:
        s.sendto(data, addr)
        x += 1
    s.close()
    endTime = datetime.datetime.now()
    deltaTime = endTime - startTime
    print("Took", deltaTime, "to send 200 000 packets")

main()
有趣的是,python的结果总是很快,平均输出为:
需要0:00:01.831531才能发送200000个数据包


因此,Go看起来确实是最慢的,但只是稍微慢一点。

这是一个毫无意义的比较,因为在普通程序中,您不会在每次发送单个数据包时都创建一个新套接字,特别是在性能受到关注的情况下,所以运行时并没有为此进行优化。如果你想提高性能,10毫秒的延迟也是相当糟糕的。在Go中,您应该使用
ListenUDP
WriteToUDP
来获得更具可比性的内容,并且您也没有关闭python中的套接字。@JimB只创建一个连接,该连接将传递给所有创建的goroutine,使用ListenUDP/WriteToUDP会产生100毫秒的延迟。这是比原始情况更糟糕的性能。更新:性能没有更差,但与以前大致相同,我的坏。您一定有其他事情发生,但我们无法知道,如果没有。例如,我的笔记本电脑每秒可以生成25000个数据包。从同一个套接字发送多个goroutine对您也没有任何好处。该接口只能以如此快的速度写入数据包,因此增加数据包上的争用并不能提高性能。@JimB-Hmm可能是这样,但我在我的macbook上进行了测试,得到了类似的结果,其中Go的性能非常差。不管怎么说,Rust似乎解决了我的问题。这是一个毫无意义的比较,因为在一个普通的程序中,你不会每次想发送一个数据包时都创建一个新的套接字,特别是当性能是一个问题时,所以运行时并没有为此进行优化。如果你想提高性能,10毫秒的延迟也是相当糟糕的。在Go中,您应该使用
ListenUDP
WriteToUDP
来获得更具可比性的内容,并且您也没有关闭python中的套接字。@JimB只创建一个连接,该连接将传递给所有创建的goroutine,使用ListenUDP/WriteToUDP会产生100毫秒的延迟。这是比原始情况更糟糕的性能。更新:性能没有更差,但与以前大致相同,我的坏。您一定有其他事情发生,但我们无法知道,如果没有。例如,我的笔记本电脑每秒可以生成25000个数据包。从同一个套接字发送多个goroutine对您也没有任何好处。该接口只能以如此快的速度写入数据包,因此增加数据包上的争用并不能提高性能。@JimB-Hmm可能是这样,但我在我的macbook上进行了测试,得到了类似的结果,其中Go的性能非常差。不管怎样,看来生锈解决了我的问题。