A possible reason is the top Go implementation doesn’t pipeline/batch the select queries, only the updates. Whereas the NodeJS Postgres driver pipelines everything. Source: https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/frameworks/Go/fasthttp/src/handlers/handlers.go Update: looks like this code was copy and pasted among all of the top go tests (fiber, fasthttp, goframe, atreugo, etc). I tried digging through the PRs to see why it was implemented this way but ran out of time. Maybe there was a good reason? I do think it’s a valid benchmark even though it’s “testing the framework not the language.” If node’s DB driver makes it easier to boost performance then that’s to its credit. If somebody wants a little fame and fortune, submit a PR to batch the selects and boost Go’s rankings! Update 2: I figured it out. Essentially, the NodeJS code is violating the requirements for the benchmark. The requirements explicitly ban the use of select batching : To be clear: bulk reads are not permissible for selecting/reading the rows, but bulk updates are acceptable for writing the updates. However the top Node implementations use select batching : for (let i = 0; i < queries; i++) { worldPromises[i] = db.find(generateRandomNumber()) } const worlds = await Promise.all(worldPromises); Although you may not see the words “batching” or “pipelining” and this is perfectly idiomatic node code and I’m sure the authors didn’t mean to do anything wrong… But queuing up query promises like this and doing Promise.all() on them all at once will trigger the Postgres driver to pipeline them. It’s a very good optimization and I’m glad idiomatic node encourages this! But at the same time it creates a fairness problem for the benchmark. If node is allowed to do this then the other frameworks should be allowed to do equivalent select batching. Update 3: looking into it even more, the benchmark rules may allow for a specific kind of “batching” that nodeJS does. Apparently there was a mega thread on this a few years ago. The node Postgres driver buffers all the queries that it gets within a node event loop and writes them to the socket together , leveraging Postgres’s extended protocol. So they are technically separate queries, but they get sent in a batch over the wire. Techempower ruled this legal . “If using PostgreSQL's extended query protocol, each query must be separated by a Sync message.” Network-level batching over the wire is acceptable (where the DB will process each query separately) but query-level coalescing is not. Where does that leave Go? Apparently v5 of the pgx driver has a pipeline API that can do this ( example usage ). It is not idiomatic Go however. Answer from 415z on reddit.com
🌐
Reddit
reddit.com › r/golang › why does go perform worse than nodejs in this test?
r/golang on Reddit: Why does Go perform worse than Nodejs in this test?
February 24, 2026 -

I found a comparison of nodejs and go performance on this site (https://www.techempower.com/benchmarks/#section=data-r23&test=update&l=zijo5b-pa5). I was interested in the fact that go loses to nodejs. Could there be something wrong there?

Top answer
1 of 12
183
A possible reason is the top Go implementation doesn’t pipeline/batch the select queries, only the updates. Whereas the NodeJS Postgres driver pipelines everything. Source: https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/frameworks/Go/fasthttp/src/handlers/handlers.go Update: looks like this code was copy and pasted among all of the top go tests (fiber, fasthttp, goframe, atreugo, etc). I tried digging through the PRs to see why it was implemented this way but ran out of time. Maybe there was a good reason? I do think it’s a valid benchmark even though it’s “testing the framework not the language.” If node’s DB driver makes it easier to boost performance then that’s to its credit. If somebody wants a little fame and fortune, submit a PR to batch the selects and boost Go’s rankings! Update 2: I figured it out. Essentially, the NodeJS code is violating the requirements for the benchmark. The requirements explicitly ban the use of select batching : To be clear: bulk reads are not permissible for selecting/reading the rows, but bulk updates are acceptable for writing the updates. However the top Node implementations use select batching : for (let i = 0; i < queries; i++) { worldPromises[i] = db.find(generateRandomNumber()) } const worlds = await Promise.all(worldPromises); Although you may not see the words “batching” or “pipelining” and this is perfectly idiomatic node code and I’m sure the authors didn’t mean to do anything wrong… But queuing up query promises like this and doing Promise.all() on them all at once will trigger the Postgres driver to pipeline them. It’s a very good optimization and I’m glad idiomatic node encourages this! But at the same time it creates a fairness problem for the benchmark. If node is allowed to do this then the other frameworks should be allowed to do equivalent select batching. Update 3: looking into it even more, the benchmark rules may allow for a specific kind of “batching” that nodeJS does. Apparently there was a mega thread on this a few years ago. The node Postgres driver buffers all the queries that it gets within a node event loop and writes them to the socket together , leveraging Postgres’s extended protocol. So they are technically separate queries, but they get sent in a batch over the wire. Techempower ruled this legal . “If using PostgreSQL's extended query protocol, each query must be separated by a Sync message.” Network-level batching over the wire is acceptable (where the DB will process each query separately) but query-level coalescing is not. Where does that leave Go? Apparently v5 of the pgx driver has a pipeline API that can do this ( example usage ). It is not idiomatic Go however.
2 of 12
116
The V8 JS engine is very very well tuned for the async loop?
🌐
Reddit
reddit.com › r/node › is there any reason to switch to golang? node.js vs golang for back-end development.
r/node on Reddit: Is there any reason to switch to golang? Node.js vs Golang for back-end development.
January 15, 2022 -

Just want to know the community opinion: from what I see the key benefit of using node.js for back-end is the same language as front-end part. If I would like to work on back-end side only, would it better to switch to golang, let’s say, to do back-end only things, and don’t care about any front-end related stuff. Have node.js developers already considered as the real “back-end” guys? Or just an JavaScript front-end switchers 😀

Top answer
1 of 5
59
Golang pros: In Node.js it is difficult to utilize full CPU cores. You will have to use cluster module (which basically is different processes communicating with each other via IPC using shared port) or use worker_threads but then they serialize messages and cannot share objects like true threads so threading in Node is awkward this way. So if you have business logic in your code which is synchronous and have too many requests then the latency of Node servers will be higher than go equivalent due to lack of concurrency and even with concurrency an equivalent go code is faster than Node as its compiled to binary. Go being statically typed means you dont have to add type validations in run time as all your go interfaces will validate data from IO calls automatically whereas in Node you will need validation libraries to validate incoming requests data (like Yup, express-validator, class validators, AJV etc) and basically everywhere you would want a strong type check in Node. In Go you get all this builtin. Go has much stronger primitives especially numbers compared to Javascript. MEMORY LEAK. Nearly all projects I worked in last 8 years in Node in different companies had memory leaks especially when websocket was involved. And i have spent countless hours profiling those Node servers by taking heap snapshots and inspecting memory usage. Sometimes it was due to library itself (ex. Socket.io inflate/deflate incoming JSON) and other times were due to developers code because of how closure in JS works and how V8 garbage collector works with mark sweep etc. I am saying in NodeJS its very easy to write a code which can leak memory and a lot of third party libraries (even established ones like socket.io) can cause leak especially when sockets are involved and those are VERY difficult to debug. Node servers consume more memory compared to equivalent Go code. Extensive standard library compared to Node.js Node pros: Has TON of 3rd party libraries to get work done compared to Go. No meta framework in Go like laravel in php or Nest.js (or Adonis.js) in Node.js world. And somehow Go community is to hostile to those ideas. It means you will end up using standard library to solve same problems which Nest.js/laravel have already solved and your solution might not be robust. It becomes prevalent if you, in your Go code, add authentication, authorization, graphql, websocket middlewares etc. Go gets messy without any meta framework or lack of good 3rd party libraries compared Node.js as the same things are easy to solve/already solved in NodeJs Extending previous point, it also means it is harder to bootstrap and build web app compared to Go as its so faster to build products with Node. Typescript as a language is MUCH fun to work and syntax of TS/JS is significantly better than Golang. Google has a history of solving problems in awkward way and always reinventing wheel just to look cool. Ex. Weird for loops, EXTREMELY weird OOP, export functions with capital letter (bad code styling by starting functions with capital letters instead of marking them with export and easier to search what is exported), receiver function (seriously to solve a problem they created another), has pointers which most other high level languages dont have and devs like not having to deal with pointers, painful string interpolation, painful to add JSON functionality, lack of generics, function can return more than 1 value, PAINFUL error handling and lack of DRY code because of it etc. Overall Go is just NOT the fun language syntactically which is a shame. 5. Faster to bootstrap ideas and overall MUCH more fun to work with by a long shot compared to Golang and overall in general. 6. Has npm modules fir just about anything though quality can be debatable. So, verdict? Overall its a tuff call. The main attraction of golang is single binary executable, easy concurrency, high speed and big standard library but its a shame that the lack of meta frameworks/small ecosystem and especially weird/poor syntax really ruin it for me significantly. Whereas Node and TS/JS is so much fun to work with with a HUGE npm ecosystem using which developers can build products significantly faster but lack of good concurrency support means hitting limits on Node server with demanding features is easy and very hard to solve given JS is not built for concurrency and servers benefit from it. The only way out would be horizontally/vertical scaling and shelling out more $ compared to Golang.
2 of 5
20
Node has a completely different API than browser JavaScript. A front end dev isn’t automatically good at Node because they know JS.
🌐
Reddit
reddit.com › r/node › node vs golang?
Node vs Golang? : r/node
June 20, 2024 - Golang to help you decide: Fast Prototyping: Tons of libraries and an active ecosystem make development faster. I/O-Heavy Applications: Great for APIs, chat apps, or real-time services due to its event-driven, non-blocking nature. Full-Stack Development: Ideal if you already use JavaScript/TypeScript for the front end. Developer Availability: Easier to hire Node developers since it's more widespread. Performance-Critical Workloads: Go shines in compute-heavy or concurrent systems, like microservices, data pipelines, or game servers.
🌐
Reddit
reddit.com › r/node › golang or nodejs?
r/node on Reddit: Golang or NodeJS?
November 23, 2022 -

Hi Reddit!

I know that this is a NodeJS thread, but I want to know your opinion about Go and NodeJS. What do you think about it?

Which of these two languages would you recommend to your friend and why? What do you think is more in demand now and for the knowledge of which of these technologies they pay more?

I am a NodeJS developer and I really love NodeJS, but also I wanna know your opinion too. I will be grateful for any opinions, thanks!

🌐
Reddit
reddit.com › r/golang › node.js 3x faster than go - what am i doing wrong?
r/golang on Reddit: Node.js 3x faster than Go - what am I doing wrong?
October 18, 2023 -

Hey folks,

we're trying to benchmark our existing Node.js solution for fetching messages from an AWS SQS queue against a Go implementation, hoping that we could achieve the same performance with less resources in Go.

On my local MacBook Pro with an M1 Pro, the Node.js application using 50 workers pulls and removes >6,000 messages per second from the queue. The following Go implementation maxes out at ~2,300 messages per second, no matter if I use 200, 400 or 2000 Goroutines.

The program itself is very simple. For x Goroutines, it creates an SQS client, fetches messages from a queue, increments a counter, deletes the message from the queue. A separate Goroutine calculates the processes messages per second and prints it out.It's the very same behaviour (imho) with the Node.js program.

Any hints what I'm doing wrong?

Thanks!

[EDIT] Since people asked: We initially started having one SQS client defined in the main function and using this one in the Goroutines - doesn't matter, exact same results. Same for "creating an SQS client per Goroutine - no difference.

[EDIT 2] Since people asked: The Node.js lib being used does the message removal automatically.

[EDIT 3] As u/radekd pointed out, the sql-consumer lib for Node does a BatchDelete of the messages after it processed them. My initial Go code does not, it deletes each message individually. After changing the Go code to use DeleteMessageBatch, it's performing identical to the Node version, leaving me with the one thing I've already assumed: this is a network limited problem in general, nothing where Go could help me to improve performance BUT it's soothing to see, that it's performing at least as fast. It doesn't matter though, whether you define the SQS client in main or per worker. Same results.

GOPHERS: Go is not slower than Node! :-D

If anyone is interested, this is the Go code performing exactly as fast as the Node version for the exact same problem:

package main

import (
	"context"
	"fmt"
	"log"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/sqs"
	"github.com/aws/aws-sdk-go-v2/service/sqs/types"
	"github.com/aws/aws-sdk-go/aws"
)

func main() {

	cfg, err := config.LoadDefaultConfig(context.TODO())
	if err != nil {
		log.Fatalf("Unable to load SDK config, %v", err)
	}

	// Create an SQS client per worker with the default configuration
	client := sqs.NewFromConfig(cfg)
	queueUrl := "https://sqs.eu-central-1.amazonaws.com/0123456789/benchmark-queue"
	receiveMessageInput := &sqs.ReceiveMessageInput{
		QueueUrl:            &queueUrl,
		MaxNumberOfMessages: 10, // same as for the Node.js version
		WaitTimeSeconds:     20, // Enable long polling like in Node.js sqs-consumer version - Benchmark: no difference regarding performance compared to short polling
	}

	var wg sync.WaitGroup
	numGoroutines := 300

	// Counter for the number of messages processed, to be incremented atomically
	var messagesProcessed int64

	// Start a separate goroutine to log processed messages every second
	go func() {
		for range time.Tick(time.Second) {
			// Since multiple goroutines can update messagesProcessed, we retrieve the value atomically.
			count := atomic.LoadInt64(&messagesProcessed)

			fmt.Printf("Messages processed per second: %d\n", count)

			// Reset the counter
			atomic.StoreInt64(&messagesProcessed, 0)
		}
	}()

	// Start multiple goroutines to process messages concurrently
	for i := 0; i < numGoroutines; i++ {
		wg.Add(1)
		go func(workerId int) {
			defer wg.Done()
			fmt.Printf("Worker %d starting\n", workerId)

			// Receive messages in a loop until the channel is closed
			for {
				receiveMessageOutput, err := client.ReceiveMessage(context.TODO(), receiveMessageInput)
				if err != nil {
					fmt.Printf("Worker %d: Error receiving messages: %s\n", workerId, err)
					continue
				}

				// If no messages are available, ReceiveMessage returns an empty slice
				if len(receiveMessageOutput.Messages) == 0 {
					fmt.Printf("Worker %d: Received no messages\n", workerId)
					continue
				}

				// Create entries for batch deletion
				var deleteEntries []types.DeleteMessageBatchRequestEntry

				for id, message := range receiveMessageOutput.Messages {
					// Create a new entry for each message
					deleteEntries = append(deleteEntries, types.DeleteMessageBatchRequestEntry{
						Id:            aws.String(strconv.Itoa(id)), 
						ReceiptHandle: message.ReceiptHandle,
					})

					// Incrementing the counter
					atomic.AddInt64(&messagesProcessed, 1)
				}

				// After processing the messages, delete them from the queue as a batch.
				deleteBatchInput := &sqs.DeleteMessageBatchInput{
					Entries:  deleteEntries,
					QueueUrl: &queueUrl,
				}

				_, err = client.DeleteMessageBatch(context.TODO(), deleteBatchInput)
				if err != nil {
					fmt.Printf("Worker %d: Failed to delete messages batch: %s\n", workerId, err)
				}
			}
		}(i)
	}

	wg.Wait()
}

This is the old code

package main

import (
	"context"
	"fmt"
	"log"
	"sync"
	"sync/atomic"
	"time"

	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/sqs"
)

func main() {
	cfg, err := config.LoadDefaultConfig(context.TODO())
	if err != nil {
		log.Fatalf("Unable to load SDK config, %v", err)
	}

	var wg sync.WaitGroup
	numGoroutines := 200

	// Counter for the number of messages processed, to be incremented atomically
	var messagesProcessed int64

	// Start a separate goroutine to log processed messages every second
	go func() {
		for range time.Tick(time.Second) {
			// Since multiple goroutines can update messagesProcessed, we retrieve the value atomically.
			count := atomic.LoadInt64(&messagesProcessed)

			fmt.Printf("Messages processed per second: %d\n", count)

			// Reset the counter
			atomic.StoreInt64(&messagesProcessed, 0)
		}
	}()

	// Start multiple goroutines to process messages concurrently
	for i := 0; i < numGoroutines; i++ {
		wg.Add(1)
		go func(workerId int) {
			defer wg.Done()
			fmt.Printf("Worker %d starting\n", workerId)

			for {
				client := sqs.NewFromConfig(cfg)
				queueUrl := "https://sqs.eu-central-1.amazonaws.com/0123456789/benchmark-queue" 

				receiveMessageInput := &sqs.ReceiveMessageInput{
					QueueUrl:            &queueUrl,
					MaxNumberOfMessages: 10, // same as for the Node.js version
					WaitTimeSeconds:     20, // Enable long polling like in Node.js sqs-consumer version - Benchmark: no difference regarding performance compared to short polling
				}

				receiveMessageOutput, err := client.ReceiveMessage(context.TODO(), receiveMessageInput)
				if err != nil {
					fmt.Printf("Worker %d: Error receiving messages: %s\n", workerId, err)
					continue
				}

				// If no messages are available, ReceiveMessage returns an empty slice
				if len(receiveMessageOutput.Messages) == 0 {
					fmt.Printf("Worker %d: Received no messages\n", workerId)
					continue
				}

				for _, message := range receiveMessageOutput.Messages {
					// Simulating message processing by incrementing the counter
					atomic.AddInt64(&messagesProcessed, 1)

					// After processing the message, delete it from the queue.
					deleteInput := &sqs.DeleteMessageInput{
						QueueUrl:      &queueUrl,
						ReceiptHandle: message.ReceiptHandle,
					}
					_, err := client.DeleteMessage(context.TODO(), deleteInput)
					if err != nil {
						fmt.Printf("Worker %d: Failed to delete message: %s\n", workerId, err)
					}
				}
			}
		}(i)
	}

	wg.Wait()
}

In case you're interested, here's the Node.js version:

import { Consumer } from 'sqs-consumer'

const cluster = require('cluster')

if (cluster.isMaster) {
    console.log(`Master ${process.pid} is running`)

    // Total count of messages processed
    let totalCount = 0

    // Fork workers
    for (let i = 0; i < 50; i++) {
        cluster.fork()
    }

    // Function to handle message counts received from workers
    function messageHandler(msg) {
        if (msg.type === 'count') {
            totalCount += msg.count
        }
    }

    // Listen for messages from worker processes
    for (const id in cluster.workers) {
        cluster.workers[id].on('message', messageHandler)
    }

    // Log the total count every second and reset for the next interval
    setInterval(() => {
        console.log(`Messages per second: ${totalCount}`)
        totalCount = 0
    }, 1000)

} else {
    let messageCount = 0

    async function handleMessage(_snsMessage) {
        messageCount++
    }

    const app = Consumer.create({
        queueUrl: process.env.SQS_QUEUE_URL,
        batchSize: 10,

        handleMessageBatch: async (snsMessages) => {
            const promises = []
            for (const snsMessage of snsMessages) {
                promises.push(handleMessage(snsMessage))
            }
            await Promise.all(promises)
        },

        handleMessage: async (snsMessage) => {
            return await handleMessage(snsMessage)
        },
    })

    // Send the message count to the master process every second, then reset to 0
    setInterval(() => {
        process.send({ type: 'count', count: messageCount })
        messageCount = 0 
    }, 1000)

    console.log('Starting SQS benchmark...')
    app.start()
}
🌐
Reddit
reddit.com › r/node › why does the us market prefer nodejs to golang?
r/node on Reddit: Why does the US market prefer Nodejs to Golang?
July 16, 2023 -

Hey guys, I have a question that needs to hear your point of view. Most US jobs for back-end I see are hiring Nodejs. Although I love Golang because it's fast and resource usage efficient. But I think the main reason is people want to code and deliver their products faster and Node.js performance is enough for them.

Hope you guys give me more insight about it. Thanks!

🌐
Reddit
reddit.com › r/golang › .net says golang 6x times slower than .net and slower than nodejs
r/golang on Reddit: .NET says golang 6x times slower than .net and slower than nodejs
October 4, 2025 -

I'm not a fan of any language but I know that there are some advantages and disadvantages of languages and framework alongside platforms matter - PHP is slow, yes it is slow comparing to any other languages but if you setup frakenPHP or swoole then is may compare with other languages -

I was just visiting dotnet page and saw that there is benchmark says 6x times faster than go and go even slower than nodejs

Why is it like this ? I'm not saying this is wrong and they are lying but, what is the explanation of this ? What does matter most such test cases?

Sources:

- https://imgur.com/a/Dx5B2kt

- https://dotnet.microsoft.com/en-us/

Find elsewhere
🌐
Reddit
reddit.com › r/golang › same algorithm is much faster in node.js than in golang. why?
r/golang on Reddit: Same algorithm is much faster in node.js than in Golang. Why?
November 19, 2021 -

Hi! I'm new to Golang and I'm trying it out.

I implemented the Kosaraju's algorithm in both Golang and node.js and measured the execution time. To my surprise, the Golang version is ~34% slower. I expected Go to be much faster than node.js.

I did my best to use the same logic and data structures for both languages to make sure I'm comparing apples to apples. I know that the algorithm itself can be improved, but I'm not looking for an algorithmic improvement, I just want to find out why Go is so much slower than node.js when both are executing the same thing.

I'll paste both scripts below. Each of them is a single file that you can run in the terminal. They'll execute the algorithm 6 times, then print the average time of the 6 executions. They expect a payload.json file in the same folder from which they'll load an adjacency matrix. I can't share my payload.json because it's too large (11 mb), but it's just a 2d matrix of random integers with 3000 rows and 3000 columns. Let me know if you need help generating it.

Can someone explain why is Go so slower than node?

graph.js

const fs = require('fs')
const { performance } = require('perf_hooks')

class Graph {
  constructor() {
    this._edges = new Map()
    this._inNeighbors = new Map()
  }

  connect(vertexFrom, vertexTo, weight) {
    if (!this._edges.has(vertexFrom)) {
      this._edges.set(vertexFrom, new Map())
      this._inNeighbors.set(vertexFrom, new Set())
    }

    if (!this._edges.has(vertexTo)) {
      this._edges.set(vertexTo, new Map())
      this._inNeighbors.set(vertexTo, new Set())
    }

    this._edges.get(vertexFrom).set(vertexTo, weight)
    this._inNeighbors.get(vertexTo).add(vertexFrom)
  }

  findOutNeighbors(vertex) {
    return new Set(this._edges.get(vertex).keys())
  }

  findInNeighbors(vertex) {
    return new Set(this._inNeighbors.get(vertex))
  }

  findVertices() {
    return new Set(this._edges.keys())
  }

  findConnectedComponents() {
    const unvisited = this.findVertices()

    const L = []

    for (const vertex of this.findVertices()) {
      this.visit(vertex, unvisited, L)
    }

    const components = new Map()

    for (let i = L.length - 1; i >= 0; i -= 1) {
      this.assign(L[i], L[i], components)
    }

    return components
  }

  visit(vertex, unvisited, L) {
    if (unvisited.has(vertex)) {
      unvisited.delete(vertex)

      for (const neighbor of this.findOutNeighbors(vertex)) {
        this.visit(neighbor, unvisited, L)
      }

      L.push(vertex)
    }
  }

  assign(vertex, root, components) {
    let hasBeenAssigned = false

    for (const component of components.values()) {
      if (component.has(vertex)) {
        hasBeenAssigned = true
        break
      }
    }

    if (!hasBeenAssigned) {
      if (!components.has(root)) {
        components.set(root, new Set())
      }

      components.get(root).add(vertex)

      for (const neighbor of this.findInNeighbors(vertex)) {
        this.assign(neighbor, root, components)
      }
    }
  }
}

function measureExecutionTime(f) {
  const start = performance.now()
  f()
  return (performance.now() - start) / 1000
}

function buildGraphAndFindComponents(data) {
  const graph = new Graph()

  for (let i = 0; i < data.length; i += 1) {
    for (let j = 0; j < data.length; j += 1) {
      graph.connect(i, j, data[i][j])
    }
  }

  return graph.findConnectedComponents()
}

function main() {
  const numberExecutions = 6
  const data = JSON.parse(fs.readFileSync('payload.json'))

  // Run one time without measuring execution time to let the JIT compiler do
  // its work
  buildGraphAndFindComponents(data)

  let totalElapsed = 0

  for (let i = 0; i < numberExecutions; i += 1) {
    const elaspedTime = measureExecutionTime(() => buildGraphAndFindComponents(data))
    console.log(elaspedTime)
    totalElapsed += elaspedTime
  }

  console.log('average: ' + (totalElapsed / numberExecutions).toFixed(2))
}

main()

graph.go

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"time"
)

type Graph struct {
	edges         map[interface{}]map[interface{}]int
	inNeighbors   map[interface{}]map[interface{}]bool
	expectedNodes int
}

func NewGraph(expectedNodes int) *Graph {
	return &Graph{
		edges:         make(map[interface{}]map[interface{}]int, expectedNodes),
		inNeighbors:   make(map[interface{}]map[interface{}]bool, expectedNodes),
		expectedNodes: expectedNodes,
	}
}

func (graph *Graph) Connect(vertexFrom interface{}, vertexTo interface{}, weight int) {
	if _, ok := graph.edges[vertexFrom]; !ok {
		graph.edges[vertexFrom] = make(map[interface{}]int, graph.expectedNodes)
		graph.inNeighbors[vertexFrom] = make(map[interface{}]bool, graph.expectedNodes)
	}

	if _, ok := graph.edges[vertexTo]; !ok {
		graph.edges[vertexTo] = make(map[interface{}]int, graph.expectedNodes)
		graph.inNeighbors[vertexTo] = make(map[interface{}]bool, graph.expectedNodes)
	}

	graph.edges[vertexFrom][vertexTo] = weight
	graph.inNeighbors[vertexTo][vertexFrom] = true
}

func (graph *Graph) FindAllOutNeighbors(vertex interface{}) map[interface{}]bool {
	keys := make(map[interface{}]bool, len(graph.edges))

	for key := range graph.edges[vertex] {
		keys[key] = true
	}

	return keys
}

func (graph *Graph) FindAllInNeighbors(vertex interface{}) map[interface{}]bool {
	keys := make(map[interface{}]bool, len(graph.edges))

	for key := range graph.inNeighbors[vertex] {
		keys[key] = true
	}

	return keys
}

func (graph *Graph) FindAllVertices() map[interface{}]bool {
	keys := make(map[interface{}]bool, len(graph.edges))

	for key := range graph.edges {
		keys[key] = true
	}

	return keys
}

func (graph *Graph) FindConnectedComponents() map[interface{}]map[interface{}]bool {
	var visit func(interface{}, map[interface{}]bool, *[]interface{})
	var assign func(interface{}, interface{}, map[interface{}]map[interface{}]bool)

	visit = func(vertex interface{}, unvisited map[interface{}]bool, L *[]interface{}) {
		if _, ok := unvisited[vertex]; ok {
			delete(unvisited, vertex)

			for neighbor := range graph.FindAllOutNeighbors(vertex) {
				visit(neighbor, unvisited, L)
			}

			*L = append(*L, vertex)
		}
	}

	assign = func(vertex interface{}, root interface{}, components map[interface{}]map[interface{}]bool) {
		hasBeenAssigned := false

		for root := range components {
			if _, ok := components[root][vertex]; ok {
				hasBeenAssigned = true
				break
			}
		}

		if !hasBeenAssigned {
			if _, ok := components[root]; !ok {
				components[root] = make(map[interface{}]bool)
			}

			components[root][vertex] = true

			for neighbor := range graph.FindAllInNeighbors(vertex) {
				assign(neighbor, root, components)
			}
		}
	}

	unvisited := graph.FindAllVertices()

	L := make([]interface{}, 0, len(unvisited))

	for vertex := range graph.FindAllVertices() {
		visit(vertex, unvisited, &L)
	}

	components := make(map[interface{}]map[interface{}]bool)

	for i := len(L) - 1; i >= 0; i -= 1 {
		assign(L[i], L[i], components)
	}

	return components
}

func measureExecutionTime(f func()) time.Duration {
	start := time.Now()
	f()
	return time.Since(start)
}

func buildGraphAndFindComponents(data [][]int) map[interface{}]map[interface{}]bool {
	graph := NewGraph(len(data))

	for i := range data {
		for j := range data[i] {
			graph.Connect(i, j, data[i][j])
		}
	}

	return graph.FindConnectedComponents()
}

func main() {
	const numberExecutions = 6

	plan, _ := ioutil.ReadFile("./payload.json")

	var data [][]int

	err := json.Unmarshal(plan, &data)

	if err == nil {
		fmt.Errorf("Error: %w", err)
	}

	// Go doesn't have a JIT compiler, but let's do the same thing we did in JS
	// anyway
	buildGraphAndFindComponents(data)

	var totalElapsed time.Duration

	for i := 0; i < numberExecutions; i += 1 {
		elaspedTime := measureExecutionTime(func() {
			buildGraphAndFindComponents(data)
		})
		fmt.Println(elaspedTime)
		totalElapsed += elaspedTime
	}

	fmt.Printf("average: %s\n", time.Duration(int64(totalElapsed)/int64(numberExecutions)))
}
Top answer
1 of 14
97
The Node one is faster because the Go is not very good. Don’t use interface with casting where perf matters. Store concrete structs
2 of 14
93
Having a crack at it now. First things first: We need if err != nil to check if the load failed, and fmt.Errorf won't do anything (the return value is an error which is discarded. Swap that for if err != nil { panic(err) } as a quick and dirty fix. Generating the payload took an ugly amount of time. I used rand.Intn(100) to get integers between 0 and 99 and ended up with a payload.json of 23MB You can't unmarshall a JSON object into a [][]int, and keys have to be strings. I settled for generating a payload like {82": [72, 90, 18... and preparing the [][]int data array with strconv.Atoi(key) before attempting to execute I have no real JS experience, so I really couldn't say if what I'm doing compares to what the JS version is doing But enough nitpicking :) Running this on a Ryzen 5 2600 the initial performance for the Go implementation was bad as expected:18844 18994 18953 18765 18577 18706 average: 18.806950083s Yep, that's ugly. First things first, let's remove the unnecessary interfaces with :%s/interface{}/int/g... 10055 9575 9611 9646 9547 9456 average: 9.648860433s Much better, but let's see what else we can find. EDIT: Have to call it for tonight with no improvements to report, but using the excellent built-in CPU profiling tools confirmed my suspicion that the map operations are slower than you'd like. Just over 29 seconds of ~43 is spent accessing maps (in runtime.mapaccess1_fast64 and runtime.mapaccess2_fast64) and another 10 seconds in runtime.mapiternext. Next up if I get to it will be understanding the algorithm better and seeing if we can give up the convenience of if _, ok := map[key] and use slices of values instead. I suspect that we're not playing to the strengths of hashmaps in this case. Expert opinions would be welcome though!
🌐
Reddit
reddit.com › r/learnprogramming › what's best for beginner: js (node.js) or golang? which is more employable?
r/learnprogramming on Reddit: What's best for beginner: JS (Node.js) or Golang? Which is more employable?
May 30, 2024 -

What do you think a person who wants to start learning web development should choose: JS (node.js) or Golang? It's been a couple of months since I started learning web development on the Odin project, but after studying the job market I found out that we have a very big competition for juniors on js, Golang has more offers (at the moment). P.s. I kinda hate CSS

🌐
Reddit
reddit.com › r/golang › why use go over node?
r/golang on Reddit: Why use go over node?
November 12, 2022 -

Looking to build a web app and was wondering if go is the right choice here? I’m familiar with node and go syntactically but not as familiar with the advantages of each language at the core level.

🌐
Reddit
reddit.com › r/node › should i choose golang or node for backend web development?
r/node on Reddit: Should I choose Golang or node for backend web development?
July 23, 2024 -

I am not a professional developer but I have experience in express/node but reading through multiple posts, it seems like Go is really catching up in backend development. But i wonder if its better in web development!!!

Go also pays well as I have read many posts and people sharing their thoughts as well. But in a web based project where the apis are also used by mobile client, is it really worth it ditch node and move to Golang?

I already know that adding golang in my skillset is really nice but If I were to choose for a solid backend developer profile, what should I choose?

Top answer
1 of 4
46
Myth #2: Node.js is interpreted This isn't a myth and the way you try to "debunk" it is plain wrong. You say the myth is "Node.js is interpreted" but then go on to explain that the JavaScript language design doesn't specify this. This is pointless because you literally named your article "Five Myths used in 'Golang vs Node.js' debate" and we're on r/node not r/javascript . It's a fact that Go applications generally run faster than Node.js applications because the latter is interpreted. It's also a fact that Go applications generally have a smaller disk and memory footprint. But sure the JavaScript language doesn't specify that so it's not real... Granted, current golang practices DO encourage channel-based Shared-Nothing concurrency – which indeed DOES scale, but to the best of my knowledge, (a) it is NOT enforceable in Go, and (b) golang run-time (unlike, say, Erlang/OTP runtime) doesn’t support/detect “pure” nonconst-global-access-free goroutines (which could be moved even to another box if necessary). So Go's model of concurrency is bad because it doesn't force you to write good code? That seems pretty rich given that you compare it to Node.js / JavaScript, which is infamous for allowing you to do the weirdest and most unexpected implicit type conversions. BTW, Node.js is Shared-Nothing by design – enforcing the only scalable model out there (and also saving us from LOTS of next-to-impossible-to-find bugs as a side benefit). That's a nice way of saying "Node.js doesn't even have actual threads, only processes to scale out, which is why the OS doesn't even allow shared memory". In other words – efficient concurrent implementations happen to be strikingly similar in Golang and Node.js There is no magic out there – and while costs of goroutines are somewhat lower than that of threads, common techniques such as going coarse-grain and limiting the number of outstanding tasks are still necessary. Ok, so because running 120,000 threads on 12 CPUs is far worse than running 12 threads on 12 CPUs and that's the same for Go and Node.js, they are the same? The basic principles of computer science don't change just because you choose a different language. But creating 12 "threads" (really, they're processes) in Node.js will cost you more overhead in terms of memory and CPU cycles than goroutines will. A fair comparison would have been to run 120,000 Node.js "threads" against 120,000 goroutines and see which performs better in terms of speed and resource consumption. effectively busting yet another myth of Golang being ok with millions of goroutines. That's not a myth. You can run millions of goroutines and they will still run, albeit far more slowly because of the still considerable overhead. But I dare you to try running millions of Java threads or Node.js "threads" and compare their respective memory footprints. Nobody runs millions of goroutines on a single machine - that's just silly. All this "myth" does is showcase Go's dynamic stack sizing in a rather eye-catching way. Myth #5: Golang performance is similar to that of C/C++ Again, what are you actually comparing here? I thought it was Go and Node.js, but I must've misclicked somewhere... Yes, Go is slower than C. But that doesn't mean anything when we compare it to Node.js. Let's take a look at some actually statistically significant representations of speed: Chart with Node.js Chart with Go Go's boxplot is a lot more spread than Node.js's but generally far faster, which means in terms of execution speed Go programs can be very fast (when compared to Node.js) or perhaps only about fast as Node.js. In terms of actually comparing Go and Node.js, this isn't really a win for Node.js, is it? Apart from that, this only accounts for execution speed. We haven't even considered memory or disk footprint yet, but it is very reasonable to assume that Go will have a significant advantage there as well. To summarize it all, I wonder if perhaps the term "myths" doesn't really do the whole thing justice. Maybe you should replace it with the word "facts".
2 of 4
12
I feel like if you're already at the point where you think node's single-/multi- threadededness matters, you're already doing stuff node isn't really designed to handle. Do you want to write a shell application in javascript because javascript is nice and easy to poop out? Use node. Do you want a simple, scalable, I/O bound web server that's in the same language as your UI enabling you to share some libraries like validation between them? Use node. Do you need CPU bound anything? Don't use node. This ain't rocket surgery
🌐
Reddit
reddit.com › r/golang › when to use golang instead of nodejs?
When to use golang instead of nodeJs? - Reddit
February 11, 2023 - For me; NodeJS when I want a website with little development time, don’t care about the API, can do all validation in the backend. Stacks like Remix and to some extent NextJS enable this. Using these stacks you can do full stack engineering with relative ease. Golang: when I want to carefully craft an API (e.g. for mobile or external), need very high performance, going for micro services, or care about the long term viability of the codebase (as Node ecosystem tends to be less stable).
🌐
Reddit
reddit.com › r/node › why not use go instead of using node.js/ts?
r/node on Reddit: Why not use GO instead of using Node.js/TS?
September 18, 2023 -

If SSR/Next.js/code sharing is not your context and if you are developing pure backend services (REST/Websocket/GraphQL anything) is there any reason to use Node.js/TS instead of GO in today's time?

So many companies are switching from Node/Python/PHP etc to GO and a constant barge of medium article praising how big performance improvement they got from moving to GO from Node etc.

The thing is, Node.js is only good for I/O but GO is good for both I/O and CPU intensive work so why feel restricted with just Node?. Moreover, if you are going to use Typescript (which you should) for static typing then why not use a proper statically typed language like GO where the types are enforced even at run time i.e. best of both worlds.

Basically with GO you get:

1] I/O and CPU bound capabilities, both (With node its just I/O and you have to be careful not to block eventloop)

2] Statically typed and runtime type safety as a result

3] No types mismatch where as with Node.js/TS it relies a lot on Deninately typed where types are separate from the actual code.

4] More performance at significantly less RAM usage. True multithreaded language

5] Low cloud bills and high scalability

6] Static binary as output so easy deployment using docker (or even without docker)

7] Big standard library so much less dependency on third party modules.

8] Functions are first class citizens so no heavy OOP design patterns like Java/C# etc.

9] Very simple language and easy to learn in a short time. So Typescript developers can learn GO quickly and be productive within weeks.

With so many advantages as above, is there any reason to develop a pure backend server in Node.js/TS compared to GO?

🌐
Yalantis
yalantis.com › home › blog › node.js vs go: which is better for backend web development?
Node.js vs Go: which is better for backend web development?
January 7, 2026 - To help you choose best backend solution for you project wisely, we compare Go and Node.js in terms of performance, error handling, scalability, and tooling.
🌐
Quora
quora.com › What-are-the-performance-differences-between-Go-and-Node-js-at-scale
What are the performance differences between Go and Node.js at scale? - Quora
Answer: It is so enormous that it isn’t even fair to compare. First of all, Go is a compiled language. Go is multithreaded by default and has so called green threads, which means you can easily create 10,000 jobs and the system will handle it with ease. Node is a single thread runtime. It is as...
🌐
Reddit
reddit.com › r/golang › go vs node.js for servers
r/golang on Reddit: Go vs Node.js for servers
February 20, 2014 -

I've been advocating Go to a friend who's in a position to make this choice. I googled for "Go vs Node.js" articles, but there's surprisingly little on the web comparing the two (and what's there is pretty bad and uses bubble sort as a basis for comparison).

Basically, unless you're going to get a lot of value out of being able to reuse code on the client and the server, I just don't see any reason to choose Node.js over Go for the types of things you'd use Node.js for.

That's how it appears to me, but I'm looking for reasonable counterarguments so I can help my friend make an informed decision that's not just based on my biases. Thanks!

Top answer
1 of 5
110
I have used both in production. I have been using Node.js for about 3 years now (I was a very early adopter. "JAVASCRIPT ALL THE THINGS!!!"). I have also been using Go for about a year now. I can tell you first hand, if you go with Go (see what I did there?), you will save yourself MASSIVE amounts of headache. Javascript is very fast. Yes this is true, V8 is very fast... however, only if you are benchmarking a simple benchmark. As soon as you start adding in complex application logic all that performance goes out the door because the virtual machine has a very difficult time correctly inferring the type and thus not being able to optimize. But if your application consists of a tight loop, it will be fast.. so its got that going for it :D Node.js: Callback hell. Must I say more? With Go, you can have each connection use a different Goroutine and use "blocking" IO AND still have better performance than Node.js. Why? because you aren't really blocking, while some IO operation is being performed on that goroutine, the scheduler does work on other goroutines/connections. So you get all the benefits of non-blocking IO without callback hells. There is absolutely NO REASON to have callback spaghetti when you can simply let the runtime take care of the nauseating details. In my 3 years of full time node.js development, I have honestly only had ONE occasion where I used the same 4 lines of code both in the server and in the client. I shit you not. There is no merit to the claim that you use the same code on the server and on the client. SURE... if you were writing a simple game and you wanted to replicate the game logic on the server to make sure nobody is cheating... it might be useful. But really ask yourself if you want to perform complex logic on the same thread that everybody else that is trying to reach the server is waiting on. No, you don't. Ohh and did I mention Node.js isn't really all JavaScript? A good portion of the pakcages on NPM are also written in Coffeescript. Hope you don't mind learning another language to deal with a package you depend on. So much for using the same language for both server and client! With Go you get type safety. This CANNOT be overstated.. except to maybe ruby-ists(jk jk! don't shoot me). Also, you get a unified tool-chain for pretty much everything you need from formating to getting modules. The one benefit you have with Node.js over Go is the massive number of packages available on NPM. But most of them are useless abandoned junk. So, even that is questionable. Testing: Lets just say that in Node.js/Javascript you would have to write tests that check the type of a variable. tsk tsk tsk... This is the only way to properly test JS and make sure nothing crazy is going on. OR!!!! here is a revolutionary idea!! let the damn compiler do it for you! MIND BLOWN!!! Anyway that is my two cents. I hope I didn't come across as a Node.js hater.. but having dealt with its warts and limitations for the past 3 years, I would only wish it on my worst enemy. Good luck
2 of 5
17
Profiling node.js programs is a pain in the ass, especially as you have to track time usage through callbacks. With Go's builtin pprof toolset, you can easily locate performance (CPU OR Memory) problems. When you do find performance bottlenecks, your optimization options are more limited in Node.js than what you can do with Go because Go exposes reference vs value semantics to the user -- and this extends to using embedded structs. Depending on what you are doing, leveraging better memory layout/access can greatly improve your performance. Go's deployment story is better, but node's dependency management is better. In general, Go is lower-level and that control comes at a cost of ramping-up and trading off some runtime flexibility. Go's type inference keeps the visual burden of types-in-code to a minimum (though it isn't HM.)