Skip to content

Commit

Permalink
upgraded concurrency chapters
Browse files Browse the repository at this point in the history
  • Loading branch information
Pismice committed Jul 18, 2024
1 parent e29c30d commit 6573463
Show file tree
Hide file tree
Showing 28 changed files with 500 additions and 225 deletions.
58 changes: 34 additions & 24 deletions TODO.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
Urgent:
- [ ] Changer le db schema, un village peut avoir plusieurs Army
- [ ] Parler du fait que jai des infos en dur sur le serveur plutot que DB pour eviter des requetes inutiles (ex: gold pour ameliorer etc)
- [ ] Rajouter au db schema si un building est en cours d upgrade ou pas (bool)
- [ ] regarder la generation de nombre aleatoires, peut etre utiliser librairie C ?
- [ ] Refactor pour pas avoir du SQL dans les handlers mais mettre ca dans des "classes"
- [ ] bouger toutes les arena vers req.arena
- [ ] https://github.com/karlseguin/http.zig?tab=readme-ov-file#testing
Projet:
- [ ] jai fait interfaces avec https://www.openmymind.net/Zig-Interfaces/ essayer interfaces avancees
- [ ] faire retourner l armee au village
- [ ] enlever les RawXXX
- [ ] + traiter les erreurs et moins de try
- [ ] + de cohesion avec les persist
- [ ] securite verifier que les actions peuvent seulement etre faites par la bonne personne
- [ ] test coverage
- [*] Tester avec GPA pour les memory leaks (shutdown et sigint a mettre dans doc si ca marche)

N importe quand:
- [ ] Tester avec GPA pour les memory leaks
- [ ] tout relier et mettre Dans mes conclusion mettre des liens vers ma doc
- [ ] Verifier que tous les premieres scripts sont exectuables
- [ ] Un script pour lancer les serveurs se serait pas mal
- [ ] https://zig.news/minosian/deciphering-many-item-types-the-skeleton-19i
- [ ] Commenter + de code et expliquer les benchmarks
- [ ] parler de zls dans les issues de mon rapport https://www.reddit.com/r/Zig/comments/12spzrh/question_about_zls/
Doc:
- [ ] Ecrire doc du projet
- [ ] Fil rouge pour partie concurence (comme dans le livre)
- [*] Epoll https://discord.com/channels/605571803288698900/1259840408545136700

Fin:
- [ ] TOUT relire (verifier que tous les premiers scripts sont executables
- [ ] sources zotero
- [ ] Changer les titres, les images et les liens pour joli pdf ou latex
- [ ] faire un autre export ou autre branche ou je mets tout joli pour word ou latex avec les bonnes images, titres, liens etc
- [ ] corriger fautes orthographe
- [ ] Affiche
- [ ] Resume publiable

Peut etre:
- [?] zig interop avec rust ?
- [?] Un script pour lancer les serveurs se serait pas mal
- [?] librairie pour chanels communication entre threads ?
- [?] std io_uring
- [?] benchmark vieux tokamak
- [?] essayer de mettre du comptime dans le projet
- [?] utiliser std.http.client pour test l api ?
- [?] rendre cookies secure Secure; HttpOnly; SameSite=Strict
- [?] Epoll https://discord.com/channels/605571803288698900/1259840408545136700
- [?] Websocket
- [?] Zig and C TODO Add other languages that can use C code and make a graph with matplotlib
- [?] CICD
- [?] debug, binutils, breakpoints, debugger
- [?] https://imfing.github.io/hextra/docs/guide/
- [?] genericite comparaison avec C

Futur:
- [!] rendre cookies secure Secure; HttpOnly; SameSite=Strict
- [!] Websocket / SSE sur page acueil pour refresh
- [!] frontend
- [!] nginx
- [!] cicd (cd)
- [!] durant presentation pas faire que des slides, mais faire aussi des exemple pour aider la comprehension
- [!] zig test en vert

Questions:
- Est ce que cest bien avec l intro quand je clique sur le titre ou faudrait mettre intro en bas et tout les solutions encapsulees ?
- c'est quoi resume publiable ?
- est ce que je peux rajouter qqch d interessant pour la concurence par exmple pour epoll ?
Binary file added affiche.doc
Binary file not shown.
2 changes: 1 addition & 1 deletion content/docs/compiler-messages.org
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#+title: Unclear compiler messages
#+weight: 10

In a language that aims to report most of its issues at compilation time, it is important to have clear and concise error messages. However at the time we are writing this it is sadly not the case. Here are a few compiler messages that you might encounter that are very hard to understand.
Overall the Zig compiler is very good at giving you clear and concise error messages. However, there are some cases where the error messages are not as clear as they could be. Here are a few examples of unclear compiler messages (at least for beginners) that you might encounter.

*** Trying to print without the incorrect struct syntax
We are going to start with the most basic one, everyone doing Zig did at least one time
Expand Down
24 changes: 14 additions & 10 deletions content/docs/concurrency/_index.org
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ The objectives of this chapter is to go in depth about the different ways to do
We are first going to explore a few definitions and concepts that are going to be useful to understand the rest of the chapter. Then we are going to explore the different ways we could achieve concurrency in Zig.
By the end you should be able to see the pros and cons of each solution and choose the one that fits your needs to develop your next Zig projects.

If you are not familiar at all the the concepts surrounding concurrency even though you should be able to follow along, I highly recommend reading [[https://github.com/luminousmen/grokking_concurrency][Grokking Concurrency by Kiril Bobrov]] that I which I found before writing those chapters because it really sums up most of concurrency concepts really good.

** Definitions
Before diving into the different ways to do concurrency in ZIG, let's first define some terms that are useful to understand the basics of concurrency that are not necessarly related to Zig. By the end of reading the definitions you should have a better understanding about the implementations we are going to see later.

It is important to note that the boundaries between some definitions are really blur and it is possible that you read a slightly different definition from an other source.

*** Coroutine
Courtines enable the management of concurrent tasks like callbacks do (which make them not concurrent by nature but they are a tool to achieve concurrency). Their great power lies in their ability to write concurent tasks like you would write sequential code. They achieve this by yielding control between them. They are used for cooperative multitasking, since the control flow is managed by themselves and not the OS. You might see them in a lot of languages like [[https://docs.python.org/3/library/asyncio-task.html][Python]], [[https://www.lua.org/pil/9.1.html][Lua]], [[https://kotlinlang.org/docs/coroutines-overview.html][Kotlin]] with keywords like **yield**, **resume** and **suspend**.
In this chapter we are going to consider that parallelism is a form of concurrency, meaning that concurency is having multiple parts of a programm running independently and parallelism is having multiple parts of a program running independently *at the same time* on multiple threads.

Coroutines can be either stackful or stackless, we are not gonna dive deep into this concept since most of the time you are going to use stackful coroutines since they allow you to suspend from within a nested stackframe (the only strength of stackless coroutines: efficiency)
*** Coroutine
Courtines enable the management of concurrent tasks, coroutines themselves are not concurrent by nature but they are a tool to achieve concurrency. Their great power lies in their ability to write concurent tasks like you would write sequential code. They achieve this by yielding control between them. They are used for cooperative multitasking, since the control flow is managed by themselves and not the OS. You might see them in a lot of languages like [[https://docs.python.org/3/library/asyncio-task.html][Python]], [[https://www.lua.org/pil/9.1.html][Lua]], [[https://kotlinlang.org/docs/coroutines-overview.html][Kotlin]] with keywords like **yield**, **resume** and **suspend**.

Coroutines can also be symmetric or asymmetric:
Coroutines can be either stackful or stackless, we are not gonna dive deep into this concept since most of the time you are going to use stackful coroutines since they allow you to suspend from within a nested stackframe, the only strength of stackless coroutines is efficiency.

**** Symmetric coroutines
The only way to transfer the control flow is by explicitly passing control **to another coroutine**.
Expand All @@ -45,8 +47,10 @@ Green threads might be better for multiple short lived tasks (eg: web server) be

Be careful when using green threads not to use blocking functions, because blocking 1 green thread might mean blocking all the green threads because they most likely all run on the same kernel thread.

An other big advantage of green threads is that you do not have to synchronize them with concepts like mutexes since only one of them can run at a time, thus avoiding data races.

*** Preemptive multitasking
In preemptive multitasking it is the underlying architecture (not us, but the OS or the runtime for exemple) that is in charge of choosing which threads to execute and when. This implies that our threads can be stopped (preempted) at any time, even if it is in the middle of a task.
In preemptive multitasking it is the underlying architecture (not the process, but the OS or the runtime for exemple) that is in charge of choosing which threads to execute and when. This implies that our threads can be stopped (preempted) at any time, even if it is in the middle of a task.

This method gives the advantage of not having to worry about a thread being starved, since the underlying architecture is going to make sure that everyone gets enough CPU time. As we can see in the 2 graphs for preemptive and cooperative multitasking, the preemptive multitasking might context switch our tasks too much, which can lead to a lot of undersiable overhead.

Expand Down Expand Up @@ -80,18 +84,18 @@ To avoid this overhead, thread pools are often used, which manage a set of threa
Event-driven programming, is basically an event loop that listen for "events". Under the hood this works by having an event loop that is going to poll for events and check regulary if an event has been emitted. Those events can be for exemple interupts or signals.

*** Asynchronous programming (non-blocking IO)
Asynchronous IO can be achieved by opening non-blocking sockets and the by using one of those 2 methods:
- polling systems (epoll, kqueue, ...) that are going to poll frequently to see if a non-blocking call got its response back. Polling systems are better if there are a lot of IO operations, but less effective when less because they are going to poll for nothing most of the time.
Asynchronous IO can be achieved by opening non-blocking sockets and then by using one of those 2 methods:
- polling systems (epoll, kqueue, ...) that are going to poll frequently to see if a non-blocking call got its response back. Polling systems are better if there are a lot of IO operations, but less effective when less because they are going to poll for nothing most of the time. Not that you don't have to use those systems calls but you can do active listening by yourself by constantly checking if the non-blocking call is ready.
- events (interupts, signals, ...) that are going to signal the caller that the response is is back and ready. Event-driven programming is less performant when the workload is high because interrupts have a big overhead.
When in this mode the execution flow of the program is unkown because we don't know when a non-blocking function might be ready for use and therefore take back the control flow of the application.

This method is useful if there a lot of IO operations, so that we can start processing other things while waiting for this IO operation.

You might think that threads can do that aswell and spawn a thread each time there is a blocking call, the thread is going to be put in non-ready mode until the blocking call is done and then re-ready, the thread wakes up and yield the result for exemple. It is true threads can handle the job aswell, but the overhead of creating and managin a thread is much higher than the overhead of creating a non-blocking call. So when you have high workload, we generally prefer non-blockion IO calls.
You might think that threads can do that aswell and spawn a thread each time there is a blocking call, the thread is going to be put in non-ready mode until the blocking call is done and then re-ready, the thread wakes up and yield the result for exemple. It is true, threads can handle the job aswell, but the overhead of creating and managing a thread is much higher than the overhead of creating a non-blocking call. So when you have high workload, we generally prefer non-blocking IO calls.

A popular library that is used for asynchronous programming is libuv, the giant behind nodejs.
A popular library that is used for asynchronous programming is [[https://libuv.org/][libuv]], the giant behind [[https://www.geeksforgeeks.org/libuv-in-node-js/][nodejs]].

Under the hood libuv is basically a single threaded [[https://docs.libuv.org/en/v1.x/design.html#the-i-o-loop][event-loop]] which is going to perform all IOs on non-blocking sockets that are polled by pollers like epoll, kqueue, ...
Under the hood libuv is basically a single threaded [[https://docs.libuv.org/en/v1.x/design.html#the-i-o-loop][event-loop]] which is going to perform all IOs on non-blocking sockets that are polled by pollers like epoll or kqueue.

*** Zig solutions
We are now going to explore in the different chapters few different ways to achieve concurrency in Zig. We are going to see the pros and cons of each solution and when to use them.
Loading

0 comments on commit 6573463

Please sign in to comment.