If anyone wants to try rewriting this and go and rust so I can do a performance benchmark against them. I’ll be really happy to do another video about that. I just don’t know if I have the time to try to re-implement this whole canvas logic and go.
6:39 our world needs more of this teaching style. definitely underrated teaching strategy: “i am assuming you got it, but i am going to pretend you don’t got it” *then proceeds to draw super intuitive diagram with explanation i love it!
Thanks man yeah, I’ll be honest. Sometimes it’s hard to teach when you don’t know the skill level of your audience so I just kind of throw things at the wall and hopefully it’s good.
@@WebDevCody it is, really, good. i appreciate the content! been trying really hard to understand the "black box" of how the tools i use work (i.e. react, nextjs, node, supabase/postgres)
In this day and age I am frustrated that we're still stuck in this message based worker dispatching single-threaded environment rather than use shared memory thread marshalling in a multi-threaded environment.
@@waleedbukhari8988 I used to be very charitable to javascript for many years, but recently I haven't had to use it much (I've just been continue to use Go and dotnet) and honestly going back to javascript for the first time in over 6 months has really shown me how brittle and hacky javascript is.
Very nice video 👌🏻 I specially loved the final part where you start optimizing. On first thought I was expecting that the sequential write operation would be taking a lot of time, but it turned out not being the case (A good reminder to check time and focus on the big offenders 👍🏻)
Love this format of videos. Straight into problem solving and easy wins once you get them. Also, interesting that you point out the diminishing rewards for such approach as well. 👏👏
People typically dislike microservices because of the added complexity, and to an extent I agree. That being said, using Node for my main server, and offloading long-running or CPU-bound operations to a Go microservice is a solid pattern. Node excels in I/O and in flexibility, and Go excels at perfomance.
@@naughtiousmaximus7853exactly what I've been doing for the last 10 years ❤ I try to stay away from any server side JS implementations as much as possible, but sometimes man's gotta do what man's gotta do. Go is a fun language though and I've used it for a bunch of algorithmic stuff. But for backend it's just not powerful enough as a language. Like no LINQ, inferior generics, no expression trees... imperative-only code is surely simple, but it's also jumpy and bug-prone, as you have to use a lot of statements to achieve you goal - let's say - to build a projection from a slice. Whereas in C# it's just a single functional (multi)line of LINQ proceeding from top to bottom.
Awesome, golang may work good here. Pls make a video on comparison between golang n node js/any js framework or serverless way to do it. Like what mental model we should have do IO intensive and for CPU intensive works.
I've used that frequently over the years when I need several node-red instances running at the same time for different parts of my application. Worker threads with communication to/from the main process to track states and share data. Makes for a really flexible server with dynamic processes.
@@Ss-zg3yj prime has a video of this. Its not even close. Controlling for hardware and code structure parity, Go is >60x faster than node, especially in long running services with high active clients due to node’s over reliance on the heap. Node is honestly so slow unfortunatey
instead of doing round-robin, I would try something like promise-limit at the top instead - in your particular case, you may be doing okay, because every task happens to be the same amount of work, but ideally you would want to launch a new task as soon as any other task is finished.
One more potential improvement can be decreasing with for the drawImage based on t (shift), I didn’t use Canvas, so not sure weather it’ll optimize it for you, but basically you don’t need to draw every single pixel for every frame.
Workers usually run on servers, thus having it as a .JS is fine? If you would like to write it in TS, you would need to compile it before being able to use it on the server. For this reason I do normally see that the worker file is just a .js file to prevent having to implement more complexity
I ran into this exact issue. I was writing in TS and compiling to single file in a docker image. Had to change it so it keeps the file structure and guarantees I know where the file will be. Atrocious.
Is it possible to move the 'frame' of the canvas rather than drawing the same image over and over? Also I would be careful at then end making the canvas a shared resource without some form of lock on it.
I love workers haven't been found chance to use them in my projects but looking forward to it. If I'm not mistaken, this worker will be run in the server right? I guess you are doing some kind of reels/tiktok creation saas? what do you think about using web workers so that this process will be done in the user's browser? Is it too much load for the users? any way, you are truly inspiration to me, love your videos, keep them coming!
I don’t know if it’s possible to do in the browser, but it might be that’s an interesting concept. I should look into yeah right now it’s for building out videos and TikTok shorts and stuff. I’m just trying to play around with. I have some fun though.
General question, i dont have any experience in backend scaling, but what do you think of using your backend as a docker image and running a bunch of them all at once with load balancer on a single VM? Is it a good pattern? (is it a microservice? idk the definition of it really) 💀
Was just looking into this as I am nearing the launch stages of an app I've been working on. In Node.js, you can use Clusters. These are sort of like threads, but they are individual Node.js processes. When your app starts, you can spin up x amount of clusters of your API in order to consume all the cores on the machine. Beyond that, you'd probably need to spin up new servers.
@@gamingbud926 little different from what I’m trying to do here. That’s scaling a single machine to handle more api requests, I’m scaling a single endpoint to do its cpu intensive tasks faster
hi cody , i have seen alot of your content , and it's cool , i also know js,ts,dmbs, ruby,go,mono repos ,git , devops , with great proficiency, i am also planning a side project , can you make a full video on like how to perfectly release a product?. i can make a full production ready product , on a validated idea. i hope you will make that video.
Conceptually would this be considered similar to how golang handles routines and has channels which you can listen on if a routine is finished. From my understanding (i might be wrong) golangs compiler does not spin actual threads but instead creates a lighter version you can say. Isn't this similar in that sense? And last thing is why are they still pushing the single thread thing if they already have this implemented to some extent is beyond me.
the go runtime has a built in scheduler, so yes go routines are not always separate dedicated threads, but they are processed from a thread group I believe
That is a possible thing I could look into. There is a way to stream to ffmpeg. All of these images can eat up a lot of memory for longer videos, so I felt it was safer to put them on disk until ffmpeg kicked off
We need to stop sayin that nodejs is single threaded. Nodejs is not single threaded anymore Every programming language in this world will use single thread by default unless and until you actually import and use the respective multithreading libraries provided by those languages and we do the same thing for nodejs by using multithreading library. During the early days of javascript there were no worker threads hence it was called single threaded at that time. But thats the case anymore. Its multi threaded now just like any other language
only for IO related tasks such as network requests, reading / writing to files. Something like drawing to a canvas which is very cpu intensive it will not
@@cianwalker1829 why not? If it does what I need but take maybe 5 seconds longer, why would I introduce more complexity on a project by bringing in yet another language and ecosystem when node was able to solve the problem? If at some point I really need to squeeze out performance, then sure I’d spent a month learning go and hoping they have packages already already for me to do canvas operations like this. But that’s also a risk because I may spend all this time just to find using a faster language wasn’t even that much faster, and now I’ve lost a month of dev time
SQLite reads and writes small blobs (for example, thumbnail images) 35% faster¹ than the same blobs can be read from or written to individual files on disk using fread() or fwrite()
Might be worth looking into that. The issue is with ffmpeg I point it to a directory and it combines all my images into a video. I’d need to look into streaming into ffmpeg I think
You could probably shave off some time if you removed some of the most frequent console logs. Would be interesting to see the perf improvement if you did. Great vid tho, cheers
Ugh i hate this in nodejs. I once had to process a CSV which turned out to be machine intensive and then we had to spawn workers and used Bull for queuing, bad experience
semaphore of 1 doesn't make any sense imo. semaphore of 1 s not semaphore. but a mutex. i'm not a js developer. but i know some js stuff. did you "fan out" the job to the workers?
Nowhere near 10x times faster 😅 Anyways, you could optimize it by batching all the work on the main thread and then send a single message to each of the workers in one go. Then for terminate you just need to receive the same amount of messages as there are workers
@@WebDevCody Was talking only about moving the work to workers, stopped after that due to the title assumed it was the only optimization you were going to do. My bad. I"m sorry. That said, it's still not 10x faster 😅. You started with 43 (not 50) and ended with 5.3 (not counting the runs without logs because that effectively gives you a different output), so that's about 8x times faster.
If anyone wants to try rewriting this and go and rust so I can do a performance benchmark against them. I’ll be really happy to do another video about that. I just don’t know if I have the time to try to re-implement this whole canvas logic and go.
Rust have the "image" crate, if you have never written Rust you are gonna enjoy it a lot, or die because the borrow checker.
I made one, I tried to comment it here two times, but it keeps getting deleted. thales-maciel/opt101
Mwaahahahaha I’m baaaAAAAaaaack!!!! Love you babe! You’re doing great!
love you!
6:39 our world needs more of this teaching style.
definitely underrated teaching strategy: “i am assuming you got it, but i am going to pretend you don’t got it”
*then proceeds to draw super intuitive diagram with explanation
i love it!
Thanks man yeah, I’ll be honest. Sometimes it’s hard to teach when you don’t know the skill level of your audience so I just kind of throw things at the wall and hopefully it’s good.
@@WebDevCody it is, really, good. i appreciate the content! been trying really hard to understand the "black box" of how the tools i use work (i.e. react, nextjs, node, supabase/postgres)
This was fun! I liked the fact that there was some improv incorporated into it and the playing around to skew better performance was solid!
In this day and age I am frustrated that we're still stuck in this message based worker dispatching single-threaded environment rather than use shared memory thread marshalling in a multi-threaded environment.
this is the state of web dev in 2024 everyone still using JS ...
What makes js good is what makes it bad.
@@waleedbukhari8988 just stop bro lol. It's not a language that should even exist in 2024 given the current state of technology
@@waleedbukhari8988 I used to be very charitable to javascript for many years, but recently I haven't had to use it much (I've just been continue to use Go and dotnet) and honestly going back to javascript for the first time in over 6 months has really shown me how brittle and hacky javascript is.
Same with python lol @perc-ai
Very nice video 👌🏻
I specially loved the final part where you start optimizing.
On first thought I was expecting that the sequential write operation would be taking a lot of time, but it turned out not being the case (A good reminder to check time and focus on the big offenders 👍🏻)
Love this format of videos. Straight into problem solving and easy wins once you get them. Also, interesting that you point out the diminishing rewards for such approach as well. 👏👏
People typically dislike microservices because of the added complexity, and to an extent I agree. That being said, using Node for my main server, and offloading long-running or CPU-bound operations to a Go microservice is a solid pattern. Node excels in I/O and in flexibility, and Go excels at perfomance.
What do you mean Node excels in I/O?
@@vinialves12362 The non-blocking async model and incredibly fast/flexible JSON (de)serialization
Or use Typescript knowledge to learn C# and you can do all this in one language.
@@naughtiousmaximus7853 Fair, C# and Kotlin are growing on me. That being said, TS/JS are more flexible and Go is faster / simpler / uses less memory
@@naughtiousmaximus7853exactly what I've been doing for the last 10 years ❤ I try to stay away from any server side JS implementations as much as possible, but sometimes man's gotta do what man's gotta do. Go is a fun language though and I've used it for a bunch of algorithmic stuff. But for backend it's just not powerful enough as a language. Like no LINQ, inferior generics, no expression trees... imperative-only code is surely simple, but it's also jumpy and bug-prone, as you have to use a lot of statements to achieve you goal - let's say - to build a projection from a slice. Whereas in C# it's just a single functional (multi)line of LINQ proceeding from top to bottom.
Awesome, golang may work good here. Pls make a video on comparison between golang n node js/any js framework or serverless way to do it.
Like what mental model we should have do IO intensive and for CPU intensive works.
I've used that frequently over the years when I need several node-red instances running at the same time for different parts of my application.
Worker threads with communication to/from the main process to track states and share data.
Makes for a really flexible server with dynamic processes.
I'd like to see node workers vs single threaded Go
its not even close
@@hamm8934 I am 100% sure multi-thread Node will beat any single-thread. stop clowning
@@Ss-zg3yj prime has a video of this. Its not even close. Controlling for hardware and code structure parity, Go is >60x faster than node, especially in long running services with high active clients due to node’s over reliance on the heap.
Node is honestly so slow unfortunatey
Im mean its all about what works for you. Its much easier to write everything in js but it has its downsides. As does go. Pick your poison
@@hamm8934 prime hates JS. he also likes HTMX 🤡
"I'm gonna just keep adding code until it works" is a very relatable sentence lol
instead of doing round-robin, I would try something like promise-limit at the top instead - in your particular case, you may be doing okay, because every task happens to be the same amount of work, but ideally you would want to launch a new task as soon as any other task is finished.
Thanks for this man! I love your content.
Good job mann.....
Love the teaching style......
This was really helpful! Thanks for sharing.
the workers api is one of my least favorite things about node. go is soooo good in this regard
Amazingly awesome! I generally don't like the video but here I've
From start I new I know this but you made a great video and I enjoyed watching it
i didnt knew the concept of semaphores before, i used to solve those problems with mutex and queues.
great work
two new things for me:
1. logs slow down the app
2. first time saw console.time and console.timeEnd
interesting video overall, good job
you must be proud of own incompetence, if you saying this out loud lol
@@Ss-zg3yjWTF....
One more potential improvement can be decreasing with for the drawImage based on t (shift), I didn’t use Canvas, so not sure weather it’ll optimize it for you, but basically you don’t need to draw every single pixel for every frame.
@Web Dev Cody Why didnt you use the cluster module?
Workers usually run on servers, thus having it as a .JS is fine? If you would like to write it in TS, you would need to compile it before being able to use it on the server. For this reason I do normally see that the worker file is just a .js file to prevent having to implement more complexity
JSDoc?
I ran into this exact issue. I was writing in TS and compiling to single file in a docker image. Had to change it so it keeps the file structure and guarantees I know where the file will be. Atrocious.
Single thread is the reason why we like HPA on kubernetes :)
__dirname is not defined because you’re in ESM.
Also you could use TS for the worker by transpiling the worker before initializing it
Is it possible to move the 'frame' of the canvas rather than drawing the same image over and over? Also I would be careful at then end making the canvas a shared resource without some form of lock on it.
context.translate(x,y)? Not sure if that re-draws but may be faster.
yeah I could try that
Doesn't sharing the canvas allow for race conditions between a ctx clear and a context ?
All workers use its own canvas
Your keyboard sounds sick, can you please share what keyboard is it?
Klack app
hi whats ur vsc theme?
Might it be beneficial to avoid terminating workers and instead reuse them to avoid the overhead of creating and terminating?
I keep them alive on the real app, this was just an example
@@WebDevCody can you provide some code example of how you reuse the workers on the real app please?
@@maxmaximus7773 just don’t terminate them. They’ll remain running and listening for messages, so just keep sending messages to them
I love workers haven't been found chance to use them in my projects but looking forward to it. If I'm not mistaken, this worker will be run in the server right? I guess you are doing some kind of reels/tiktok creation saas? what do you think about using web workers so that this process will be done in the user's browser? Is it too much load for the users?
any way, you are truly inspiration to me, love your videos, keep them coming!
I don’t know if it’s possible to do in the browser, but it might be that’s an interesting concept. I should look into yeah right now it’s for building out videos and TikTok shorts and stuff. I’m just trying to play around with. I have some fun though.
i would love to see a video about doing the same job in go
Be careful, shared mutable state is very dangerous
General question, i dont have any experience in backend scaling, but what do you think of using your backend as a docker image and running a bunch of them all at once with load balancer on a single VM? Is it a good pattern? (is it a microservice? idk the definition of it really) 💀
If I need scale I’d run my docker container on a lambda and give it 10gb of memory. It should work just fine
Was just looking into this as I am nearing the launch stages of an app I've been working on. In Node.js, you can use Clusters. These are sort of like threads, but they are individual Node.js processes. When your app starts, you can spin up x amount of clusters of your API in order to consume all the cores on the machine. Beyond that, you'd probably need to spin up new servers.
@@gamingbud926 little different from what I’m trying to do here. That’s scaling a single machine to handle more api requests, I’m scaling a single endpoint to do its cpu intensive tasks faster
so you're basically recreating Goroutines in JavaScript
Not recreating, this is built into node
@@WebDevCody right, I didn't mean that in the literal sense
hi cody , i have seen alot of your content , and it's cool , i also know js,ts,dmbs, ruby,go,mono repos ,git , devops ,
with great proficiency, i am also planning a side project , can you make a full video on like how to perfectly release a product?.
i can make a full production ready product , on a validated idea.
i hope you will make that video.
My biggest question is how do you have 11 cores? Did they forget to put 1 more core into your processor?
Idk it’s a mac book
@@WebDevCody They have to be brave!
While i love your optimizations, working with js seems to try to get supercar performances with a station wagon.
Conceptually would this be considered similar to how golang handles routines and has channels which you can listen on if a routine is finished.
From my understanding (i might be wrong) golangs compiler does not spin actual threads but instead creates a lighter version you can say.
Isn't this similar in that sense?
And last thing is why are they still pushing the single thread thing if they already have this implemented to some extent is beyond me.
the go runtime has a built in scheduler, so yes go routines are not always separate dedicated threads, but they are processed from a thread group I believe
What VS Code theme is that?
Bearded theme fest web dev cody
Using ArrayBuffer instead of the canvas api might be even faster.
What about "writing" the image to a memory array and not to disk?
That is a possible thing I could look into. There is a way to stream to ffmpeg. All of these images can eat up a lot of memory for longer videos, so I felt it was safer to put them on disk until ffmpeg kicked off
how about removing consoles ? will it change a little? just curios EDIT: ignore, you did it in last minutes :)
Idea - Maybe write the same app with Go/Rust and see how the performance differs?
Primeagen had a video like this with websockets
Yeah, I wanna try if I get time
Pretty sure may be massively faster in a compiled language
We need to stop sayin that nodejs is single threaded. Nodejs is not single threaded anymore
Every programming language in this world will use single thread by default unless and until you actually import and use the respective multithreading libraries provided by those languages and we do the same thing for nodejs by using multithreading library.
During the early days of javascript there were no worker threads hence it was called single threaded at that time. But thats the case anymore. Its multi threaded now just like any other language
Not*
“It’s not going to be that efficient” - does its basic asynchronous architecture not kind of negate its single-threadedness to a large extent?
only for IO related tasks such as network requests, reading / writing to files. Something like drawing to a canvas which is very cpu intensive it will not
@@WebDevCody ah yes HTTP aside, actually processing things - JS shouldn’t REALLY be used for this if possible but suppose front end devs have to?
@@cianwalker1829 why not? If it does what I need but take maybe 5 seconds longer, why would I introduce more complexity on a project by bringing in yet another language and ecosystem when node was able to solve the problem? If at some point I really need to squeeze out performance, then sure I’d spent a month learning go and hoping they have packages already already for me to do canvas operations like this. But that’s also a risk because I may spend all this time just to find using a faster language wasn’t even that much faster, and now I’ve lost a month of dev time
@@WebDevCody sorry yes I meant what I said as a question more than a statement.
@@cianwalker1829 oh, to answer your question then, node works fine and runs millions of services around the world currently.
SQLite reads and writes small blobs (for example, thumbnail images) 35% faster¹ than the same blobs can be read from or written to individual files on disk using fread() or fwrite()
Might be worth looking into that. The issue is with ffmpeg I point it to a directory and it combines all my images into a video. I’d need to look into streaming into ffmpeg I think
You could probably shave off some time if you removed some of the most frequent console logs. Would be interesting to see the perf improvement if you did. Great vid tho, cheers
Should have watched till the end before commenting lol
Ugh i hate this in nodejs. I once had to process a CSV which turned out to be machine intensive and then we had to spawn workers and used Bull for queuing, bad experience
Hell it's about time... 😂
Nodejs is NOT “single threaded” for quite a long time.
They use a thread pool under the hood for io. We all know what I’m talking about.
woow multithread for node is so complicated, in go is really simple with channels
yes it really is
thx
That's cursed API
@@vinialves12362 yeah it’s a bit rough
Try running it with a bun
Great 👍
Man please mention theme name. The theme is really beautiful ❤
bearded theme feat web dev cody
@@WebDevCody is this available for download? I want this theme for my vs studio. Edit:- found it thank you so much
You should start to watch some Erick Wendel's videos... One of his videos is exactly about this
I’ll try to remember to check it out
very nice video, can I get the source code please to do some more analysis
I guess you could just use Bull at that point.
fun vid
Web devs in 2024 suddenly discovering parallelism. Wait until you hear about not blocking on IO.
I invented concurrency
Nice theme what's the name pls
well yeah concurrency is usually a lot faster than a loop
Who would have thought?! Usually I just overclock my ec2 instances so the electrons fire faster!
semaphore of 1 doesn't make any sense imo. semaphore of 1 s not semaphore. but a mutex.
i'm not a js developer. but i know some js stuff. did you "fan out" the job to the workers?
I round robin to the workers. Gpt calls this a binary semaphore. Whatever it’s called, it helps limit work in progress and that’s all I care about.
@@WebDevCody you haven't reach the ceiling yet, also need a bit of work with the graph.
@@bokunochannel84207 ceiling for the workers being able to process more? Not sure what you mean
@@WebDevCodyyea i mean, a binary semaphore is basically just a mutex lol
Use mjs for worker
Nowhere near 10x times faster 😅
Anyways, you could optimize it by batching all the work on the main thread and then send a single message to each of the workers in one go. Then for terminate you just need to receive the same amount of messages as there are workers
wait, it took 50 seconds without this change, and ran in under 5 seconds after the change. what's 50 / 5? 10 🤣
@@WebDevCody Was talking only about moving the work to workers, stopped after that due to the title assumed it was the only optimization you were going to do. My bad. I"m sorry.
That said, it's still not 10x faster 😅. You started with 43 (not 50) and ended with 5.3 (not counting the runs without logs because that effectively gives you a different output), so that's about 8x times faster.
@@lengors7327 😜 you got me, I might have done some rounding
this only works if you have a cpu that has multiple threads. your average 1vcpu vps wont work here
FIRST!!!!
flex
LET'S GO! good job babe
just use a multithreaded language at this point
this is unnecessary complex
You don’t think bringing in another language in another ecosystem is not adding its own complexity?
Just give up, the specific stack you are using is not made for performance, accept your fate
Would love to see you do this again with go channels/goroutines
Promise.all?
Doesn’t do anything for cpu intensive tasks. It only helps for IO bound operations.