Schedulable lightweight virtual processes and concurrent loops P&L: -11.5 (≃ -96 EUR)
Imagine a nested for loop, it is composed of multiple loops. We can simulate concurrency by executing parts of loops and rapidly switch between them.
This is what a kernel scheduler does and I think it's a very interesting part of an operating system. Unfortunately most programs are not written to be multithreaded so computers use very little of resources available to them.
Perrašykite Python kodą Java, kad būtų galima naudoti tikrą daugiagiją Įdiekite kilpos paleidimo gijas, kurios pakartotinai bando vykdyti N-ąjį produktą, atitinkantį tą gijos numerį
Rewrite Python code in Java so true multithreading can be used Implement loop runner threads that repeatedly try execute Nth product that matches that thread number
2 valandos Esu gana patenkinta tuo, ką sukūriau. Manau, kad API galėtų būti geresnė. Arba rezultatų laukimo įgyvendinimas galėtų būti geresnis. Skaičiavimas, norint pamatyti, ar yra naujų rezultatų, yra brangus dėl įdėtų kilpų. Manau, kad tai būtų galima padaryti geriau. Idealiu atveju įdėtoms kilpoms reikia tik kelių divmod instrukcijų ir papildymų. Priešingu atveju jie turi dominuoti naudojamuose veiksmuose.
2 hours I am fairly happy with what I created. I think the API could be better. Or the implementation of waiting for results could be better. The calculation to see if there are any new results is expensive due to nested loops. I think this could be done better. Ideally nested loops should only take a few divmod instructions and additions. Otherwise they shall dominate performance used.
2-4 valandas nepamenu, kada pradėjau
Gaunu pasikartojančius įrašus.
Pirminė kilpa atrodo taip:
už laišką raidėmis: už skaičių skaičiais:
simboliui simboliuose:
Tada bandau jį išplėsti nauja lygiagrečia kilpa vidinės kilpos viduje.
Bet kiekviena iteracija atrodytų taip pat! Tai nėra lygiavertis šiam:
už laišką raidėmis: už skaičių skaičiais:
simboliui simboliuose:
įdėtiems kodams: jaustams įdėtoje: spausdinti (raidės skaičiaus simbolis įdėtas jaustukas)
Man reikia tam tikro būdo, kaip išplėsti kilpą per tam tikrą skaičių kilpų, pavyzdžiui, kilpų medį.
2-4 hours I cannot remember when I began
I get duplicate entries.
The parent loop looks this:
for letter in letters: for number in numbers: for symbol in symbols:
Then I try extend it with a new concurrent loop inside the innerloop.
But each iteration would look the same! It's not equivalent to this:
for letter in letters: for number in numbers: for symbol in symbols: for nested in codes: for emoji in nested: print(letter + number + symbol + nested + emoji)
I need some way of extending the loop through an arbitrary number of loops, like a tree of loops.
Tam skyriau 1 val. Aš tikrai nebuvau nusiteikęs tobulėti, bet buvau pastūmėtas.
I spent 1 hour on this. I wasn't really in the mood for development but pushed through.
Supratau savo logikos klaidą. 0 gija yra atsakinga už 0-8 ciklo iteracijas 1 gija yra atsakinga už 8-16 2 gija yra atsakinga už 16-24 Ir taip toliau Šiuo metu aš atlieku ciklo iteracijas netinkamoje gijoje dėl matematinės logikos, kad netvarkau apvyniojimo. Aš naudoju modulio operatorių. Idealiu atveju kiekvienas stulpelis iškviečiamas tik jo diapazone.
I realised my bug in my logic. Thread 0 is responsible for loop iterations 0-8 Thread 1 is responsible for 8-16 Thread 2 is responsible for 16-24 And so on I'm currently executing loop iterations on the wrong thread due to a mathematical logic of not handling wraparound. I use the modulo operator. Ideally each ticker is only called on the thread for its range.
Turiu problemą, kurią turiu išspręsti. Kuris nesusijęs su lygiagretumu.
Įsivaizduokite, kad turiu įdėtą kilpą, kuri atrodo taip
``` Raštui raidėmis:
Dėl skaičiaus skaičiais:
Spausdinti (raidės numeris)
Simboliams simboliuose:
Spausdinti (raidės simbolis) ```
Noriu, kad šios trys kilpos veiktų vienu metu. Vienas iš būdų yra pasirinkti paleisti funkciją pagal indeksus! Ir apvaliai sujunkite skaičius ir raides. Taigi gauname
A1
A÷
A2
A×
Šio metodo problema yra ta, kad kilpos nėra atskirtos. Jie yra viena kilpa, kuri buvo sujungta.
Manau, kad galiu išspręsti šią problemą, kai kolekcijas sudaro kelios kolekcijos. [Raidės, [skaičiai, simboliai] Ir rinkimasis iš kiekvieno subsąrašo apvalios veiklos ir kilpų atskleidimas kaip atskiri objektai.
I have a problem I need to solve. Which isn't related to the parallellism.
Imagine I have a nested loop that looks like this
``` For letter In letters:
For number in numbers:
Print(letter + number)
For symbol in symbols:
Print(letter + symbol) ```
I want these three loops to run concurrently. One approach is to pick the function to run based on the indexes! And merge the numbers and letters together round robin. So we get
A1
A÷
A2
A×
The problem with this approach is that the loops aren't separate. They're one loop that has been merged.
I think I can solve this by causing collections to be a multi collection. [Letters, [numbers, symbols] And picking from each sublist round robin and exposing the loops as separate objects.
Sukūriau kelių gijų versiją be Joinable kilpų. Bet šiuo metu darau pertrauką. Man reikia kažkaip pririšti daugiasriegius siūlus prie sujungiamos kilpos. Kai sujungiama kilpa gauna 2 ar daugiau reikšmių, ji toliau apdorojama. Tai leidžia padalinti ir sujungti dujotiekio apdorojimą. Noriu, kad sujungti procesai įvyktų kuo greičiau ir būtų daugiagijai. Mano projekte – kurį dar neįdiegsiu Java – kiekviena gija turi planavimo priemonę, kuri dar kartą patikrina, ką galima pažymėti, ir pažymi ją. Problema yra erkių padalijimas per siūlus, nesunku, jei yra tik vieno lygio žymės. Vienu metu galite pažymėti 8 partijas. Atskirose gijose. Mano pavyzdyje yra įdėtas 3 rinkinių ciklas ir padalintas į dvi užduotis, o tada šios dvi užduotys sujungiamos į vieną užduotį, kad būtų išspausdinti rezultatai. Noriu, kad įdėtos kilpos, atskiros užduotys ir sujungtos užduotys būtų vykdomos paketais. Reikia būdo siųsti lygiagrečias kilpas į senas gijas. Galėtų turėti bendrą kolekciją, vadinamą „tick pool“, kurią tikrina visos gijos. Dabartinis gaminio numeris susietas su gija. Pasirinkau ÷ 8, nes 64 yra 8 kartotinis. Išvalykite partijų skaičių viename siūle.
```
Nors (tiesa) {
Dėl kilpos erkių baseine:
Jei srovė[kilpa] < thisThreadN[kilpa]:
srovė [kilpa] = srovė [kilpa] 1
NewTickersOrResult = Loop.tick()
Jei NewTickersOrResult.isTickers:
Kitas:
}
```
I created a multithreading version of this without the Joinable loops. But at this time I am taking a break. I need to somehow tie the multithreading to the joinable loop. When Joinable loop received 2 or more values, it continues processing. This allows a split and merge in pipeline processing. I want joined processes to occur as soon as they can and to be multithreaded. In my design - that I am yet to implement in Java - each thread has a scheduler that rechecks what can be ticked and ticks it. The problem is splitting ticks over threads, it's easy if there is only one level of tickers. You can just tick batches of 8 at a time. In separate threads. My example has a nested loop of 3 collections and a split into two tasks and then those two tasks join into one task to print out the results. I want the nested loops, separate tasks and the joined tasks to be executed in batches. Kind of need a way to send concurrent loops to old threads. Could have a shared collection called the tick pool which is checked by all threads. The current product number is associated with a thread. I picked ÷ 8 due to the 64 being a multiple of 8. Clean number of batches per thread.
```
While (true) {
For loop in tick pool:
If current[loop] < thisThreadN[loop]:
current[loop] = current[loop] + 1
NewTickersOrResult = Loop.tick()
If NewTickersOrResult.isTickers:
Else:
}
```
Galvoju, kaip panaudoti kelių procesoriaus branduolių našumą. Reikia drastiškai permąstyti, kaip rašome kodą!
Man pasirodė, kad kilpos gali būti trivialiai lygiagrečios su mano dizainu.
N = 0 .. N = 3×3×3
Jei pasirinktumėte žymėjimo metodą visose gijose su kiekviena N, galėtumėte paleisti visą kilpą vienu ypu.
I am thinking of how to use the performance of multiple CPU cores. It requires a drastic rethinking of how we write code!
It occurred to me that loops could be trivially parallelized with my design.
N = 0 .. N = 3×3×3
If you ran the tick method on all threads with every N, you could run the entire loop in one go.
Turiu parašyti Joinable Ticker, kuris laukia įvesties iš kelių žymenų prieš siųsdamas išvestį. Tai leidžia mums sukurti vamzdynus, kurie skaidosi ir susilieja.
I need to write a Joinable Ticker that waits for inputs from multiple tickers before sending output along. This lets us create pipelines that split and merge.
Pridursiu, kad vienam siūlui reikia tik vienos while (true) kilpos. Visa kita gali būti vienu metu suplanuota gijoje.
I shall add that you only need one while (true) loop per thread. Everything else can be concurrently scheduled within a thread.
Štai kodėl aš tai vadinu virtualiu lygiagrečiu. Norėdami užtikrinti IO lygiagretumą, turėsite naudoti gijas Neįmanoma sukurti visko, kas sukasi amžinai arba blokuoja. Taigi toliau parašysiu visą savo kodą, kad niekada neblokuočiau ir nepasikartotų. Tai svarbi pamoka, kurią išmokau kurdamas daugiasriegio planavimo priemonę.
Blokavimas programai nematomas. Programa nežino, kad ji blokuoja. Turite žinoti, kad metodas gali blokuoti, kad jį apeitų. Kita mano idėja yra lygiagreti, o darymo ciklas, kuris pakeičia blokavimą į neblokuojantį per sintaksinį cukrų. Tai atrodo taip
A1 = lygiagreti, o { Buf = socket.recv(1024) } Daryk { Lygiagretus (Socket socket : sockets) { Socket.send(buf) } } Crossmerge A1
Ši sintaksė sukasi kelias gijas, kurias blokuoja gavus duomenis. Ir kiekvienam iš jų jis sukasi siūlą gijų telkinyje, kad galėtų jį apdoroti ir lygiagrečiai siųsti į kiekvieną jungtį.
Dar viena mintis, kurią turiu, yra pakeisti prioritetinę vykdymo tvarką. To kodo planuotojas kiekvieną kartą sutvarko žymes ta pačia tvarka. Nėra jokios priežasties, kodėl kai kurių kilpų negalėtume vykdyti labiau nei kitų.
That's why I call it virtual concurrency. You would need to use threads to provide IO concurrency Anything that loops forever or blocks cannot be composed. So I shall write all my code going forward to try never block and be reetrant. This is an important lesson I learned while developing my multithreaded scheduler.
Blocking is invisible to the program. The program isn't aware it is blocking. You need to know that a method can block to work around it. My other idea is a parallel while do loop which changes blocking to be non blocking through syntactic sugar. It looks like this
A1 = parallel while { Buf = socket.recv(1024) } Do { Parallel for (Socket socket : sockets) { Socket.send(buf) } } Crossmerge A1
This syntax spins up multiple threads to block on receiving data. And for each one it spins up a thread in a thread pool to handle it and send it to every connection in parallel.
Another idea I have is to change the priority execution order. That scheduler in that code round robins the tickers in the same order every time. There's no reason why we cannot execute the loops some more than others.
Įdomus. Jūs nenaudojote savojo [concurrency in Python] palaikymo (https://docs.python.org/3/library/concurrency.html) ir naudojote tik pagrindinį išvardinimą, indeksavimą ir priskyrimą. Manau, kad to reikia suprasti. Tai turi edukacinę vertę.
Interesting. You did not use any native support for concurrency in Python, and used only basic enumeration, indexing, assignment. I guess, that is what it takes to understand. This has educational value.