Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: anonym 30. 07. 2018, 19:27:22

Název: Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 30. 07. 2018, 19:27:22
Zrovna jsem přemýšlel nad tím, proč Java spotřebuje nutně na každou blokující operaci jeden thread. V případě Socketu jsem si myslel, že v C++ je možné definovat pro Socket funkci, která bude sloužit jako obsluha pro přerušení z OS. Třeba na Arduinu si totiž můžu definovat funkci jako obsluhu přerušení při nově přijatých datech třeba z SPI. CPU při tomto přerušení přeruší úlohu a spustí obslužnou funkci.

Takže jsem měl představu, že když přijde nový packet, tak se vyvovalá kaskáda přerušení až do programu, kde se tato událost následně oblouží.

Nicméně zjistil jsem, že i v C++ obsloužení socketu umožňuje jen ty možnosti, co v Javě: buďto blokující čtení a nebo dotazování na nová data ve smyčce. Což mě teda trochu zklamalo.

Proč OS tento systém přerušení zazdí a nedovolí událost (nový packet, stisknutá klávesa) zpropagovat až do programu?

A druhá otázka, jak je na úrovni OS řešeno to, když vlákno čeká při blokující operaci? Tady doufám, že tam skutečně je nějaký inteligentní systém, kdy si kernel hlídá které vlákno zrovna čeká na jakou událost a když ta vypukne, tak hned ví, které vlákno má probudit. Tzn. doufám že OS nepřepíná mezi vlákny a nedělá interně něco jako

while(avalable())

ale že má nějakou tabulku typu Vlákno<->Přerušení, takže když přijde nový packet na port 666, tak on hned ví, že vlákno XYZ na to čeká.

Nicméně i přesto tento model dneska vede k problémům u výkonných webových služeb, které musí dokázat obsloužit třeba tisíce requestů za vteřinu, protože to nutí dělat aplikace, které na každý request spotřebují minimálně jeden thread. Např. u Javy EE to tak je.

PS: Jirsák má zakázáno odpovídat.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: v 30. 07. 2018, 19:30:54
epoll?
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: backup 30. 07. 2018, 19:49:10
proc blokujici?

inu, protoze je to smysluplne. Priznam se, ze jsem se obcas take nekdy za ta leta zamyslel, proc nektere veci funguji jak funguji. A zatim jsem vzdy zjistil, ze ten Thompson a Ritchie to vedeli spravne a smysluplne.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: JSH 30. 07. 2018, 19:58:00
Psát asynchronní obsluhu událostí je záhul na mozkovnu. Takže se to dělá jen pokud není zbytí. Vlákno, které čeká na data, toho zas tolik nespotřebuje. Žádný modernější OS při čtení dat ze socketu aktivně nečeká, ale dotčené vlákno uspí. Ve většině případů to nepřináší žádný zásadní problém s výkonem. Pro pár IO operací stačí spustit blokující operaci v jiném vlákně, takže běžná api vypadají podle toho.

Pokud to nestačí (hodně zatížený server a podobně), pak má každý OS nějaký platformně specifický způsob, jak na to. V Linuxu může jedno vlákno obsluhovat tři zadeke socketů najednou přes epoll. Na Windowsech se dá spustit asynchronní operace, která po skončení pošle zprávu.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: MD 30. 07. 2018, 20:03:57
Citace
Proč OS tento systém přerušení zazdí a nedovolí událost (nový packet, stisknutá klávesa) zpropagovat až do programu?
Nevím, jak OS obecně, ale třeba Windows má implementaci socketů dost asynchronní (jak v usermode, tak zejména v kernelu), viz například funkce WSARecv, která svými parametry přímo vyzývá k asynchronnímu použití. Provádět tyto operace synchronně je však pro programátora mnohem jednodušší.

Co se týče Arduina, podívejte se blíže, jak fungují SPI, I2C, UART a podobné komunikační mechanismy. Přerušení je obvykle jejich součástí, takže není divu, že vám jej knihovny Arduina dovolují využít.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: klass 30. 07. 2018, 20:12:30
Protote ji máš tak nastavenou, můžeš si ji nastavit i jako neblokující.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 30. 07. 2018, 20:38:45
Psát asynchronní obsluhu událostí je záhul na mozkovnu. Takže se to dělá jen pokud není zbytí. Vlákno, které čeká na data, toho zas tolik nespotřebuje. Žádný modernější OS při čtení dat ze socketu aktivně nečeká, ale dotčené vlákno uspí. Ve většině případů to nepřináší žádný zásadní problém s výkonem. Pro pár IO operací stačí spustit blokující operaci v jiném vlákně, takže běžná api vypadají podle toho.

není pravda. S použitím coroutin nebo promisů je to jednodušší než s použitím vláken. Kód je téměř identický, ale nemusíte řešit race conditions. Asynchronní obsluhu socketů dnes zvládá každý webař.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 30. 07. 2018, 20:52:28
Zrovna jsem přemýšlel nad tím, proč Java spotřebuje nutně na každou blokující operaci jeden thread.

protože blokující = zablokuje vlákno.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 30. 07. 2018, 21:00:28
Nicméně zjistil jsem, že i v C++ obsloužení socketu umožňuje jen ty možnosti, co v Javě: buďto blokující čtení a nebo dotazování na nová data ve smyčce. Což mě teda trochu zklamalo.

tu smyčku si nemusíš psát sám. Můžeš použít třeba Boost.Asio nebo libuv.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: borekz 30. 07. 2018, 21:14:16
Napsat smyčku je ten nejmenší problém. Těžší je např. parserovat text s LL gramatikou v průběhu načítání. Rekurzivní parser by se implementoval obtížně.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: František Ryšánek 30. 07. 2018, 21:17:54
Spíš je otázkou, jaký programátorský nebo programovací styl byste na ten socket ještě chtěl navěsit, pokud Vám nestačí poll() nebo blokující recv() ? Jako že prostě zaregistrovat callback?

Pak je třeba si uvědomit, co by znamenalo takový callback zavolat. Buď by Libc musela na pozadí mít nějaké vlákno, které ty callbacky bude obsluhovat. Nebo pro každé "probuzení callbacku" nějaké to vlákno odštípnout. A pokud ne plnotučné vlákno, tak aspoň nějaký ten tasklet... ale o těch jsem slyšel jenom v kernelu. Nebo by ty callbacky prováděl přímo scheduler? V zásadě pokud by se to mělo dělat nějak "lehkotonážně", jako že ten "callback prostě systém zavolá v nějakém svém kontextu", tak je třeba ten kontext napřed nějak vymyslet/zavést a zřejmě by pak z toho plynula nějaká omezení, co ten callback smí v takovém kontextu dělat.

Vlastně mě jedna analogie napadá: POSIXové signály v UNIXu. Pro signály se taky registrují callbacky. Ale stejně je zase logika taková, že signálů je velmi omezený počet a signál se doručuje vláknu jako celku. Dál tam tuším není jak předat nějaký další argument (uživatelský kontext) - jediným argumentem handleru je číslo signálu. Takže třeba pokud by Váš program v jednom vlákně obsluhoval víc socketů tím způsobem, že by si nechal posílat signály (a třeba by v hlavní smyčce prostě chrápal), tak by při příchodu signálu neměl jak zjistit, který socket zrovna dostal data - aniž by je všechny postupně olíznul. To už mi přijde přímočařejší, použít sockets API a jeho funkci poll().

Nebyl náhodou původní Winsock (ten bez čísla, před Winsock2.dll) řešený tak, že člověk dostával od socketů v zásadě Window Messages? Jak to řekl Linus o event-driven programování? "... It feels good, but it doesn't actually get anything done." ?

Ona i ta obsluha přerušení má svá omezení, podobně jako callback zvaný "signal handler", který si můžete zaregistrovat v user space.

Pravda v souvislosti se sockety se signály zřejmě nepoužívají, přinejmenším nikoli pro "užitečnou práci" socketu = lifrování dat. Pokud se někde mluví o signálech v souvislosti se sockety, tak obvykle v tom smyslu, že funkce recv() spinkající na socketu může být "mimořádně probuzena" signálem, pokud si pár věcí kolem takto nastavíte. Čili ne že by ten signál přišel od socketu jako upozornění na příchozí data. Spíš se to používá na mimořádné věci, jako třeba timeout ("už chrápeš nějak moc dlouho, dlouho nepřišla žádná data") nebo při ukončení programu, pokud se snažíte o graceful shutdown.

=> to už mi přijde víc košer, uloupnout si pro obsluhu každého socketu svůj vlastní plnotučný user-space thread, kde můžu většinu času sladce spinkat v recv() a pokud nějaká data přijdou, tak se nemusím omezovat v paletě "vyjadřovacích prostředků". A pokud potřebuju odvést nějakou práci a přitom zase rychle znovu čekat na další data, tak to roztrhnout na více vláken, přidat nějakého konzumenta, data předávat skrz frontu s mutexem apod. Režie vláken není nijak hrozná.

Ohledně Vaší otázky "jak to dělá process scheduler"... no obecně řadí procesy do dvou kategorií: "běžící" a "spící". Process scheduler žije v kernelu a má nějaké tabulky nebo fronty procesů/vláken/tasků, se kterými žongluje. Když se scheduler rozhoduje, kterému procesu dá veslo tentokrát, vybere si logicky z těch, které jsou cinknuté jako "runnable" (a na ten výběr je nějaký dost chytrý algoritmus, navíc laditelný). Jestli má CPU scheduler nějaký vychytaný rychlý index (hash/btree) kde klíčem je sledovaný "systémový zdroj" (třeba socket) a hodnotou pointer na "struct task", to se mě moc ptáte :-) Poměrně blízko u "pramene" je třeba funkce schedule() = usínající proces ji zavolá, a ona se vrátí v jiném procesu, kterému dal CPU scheduler zrovna "veslo" :-) Je vošajstlich vymýšlet moc složité rozhodovací chytristiky zrovna v tak exponované funkci jako je scheduler - spouští se hodně často (tuším spíš při každém přišedším IRQ, než jenom pravidelně podle timeru) takže třeba balancovat v scheduleru nějaký strom mi přijde možná za hranou.

Našel jsem jedno online čtení (https://notes.shichao.io/lkd/ch4/) které trochu popisuje reálie v Linuxu - bohužel odpověď zrovna na Vaši otázku tam možná přímo nebude. Ale vidím tam pár nápadů, odkud začít číst zdrojáky kernelu :-)
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 30. 07. 2018, 21:19:25
Napsat smyčku je ten nejmenší problém. Těžší je např. parserovat textový formát v průběhu načítání.

Stejně jako synchronně. Dobré knihovny mají file-like abstrakci nad sockety.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 30. 07. 2018, 21:31:18
příklad tcp komunikace po řádcích v pythonu (s použitím knihovny curio (http://curio.readthedocs.io/en/latest/tutorial.html#a-stream-based-echo-server)).

Kód: [Vybrat]
from curio import run, spawn, tcp_server

async def echo_client(client, addr):
    print('Connection from', addr)
    s = client.as_stream()
    async for line in s:
        await s.write(line)
    print('Connection closed')

if __name__ == '__main__':
    run(tcp_server, '', 25000, echo_client)

s proměnnou s pracujete stejně jako se souborem, jen před blokující operace přidáte await a před for smyčku dáte async. Žádná věda.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: kimec 30. 07. 2018, 23:46:02
Zrovna jsem přemýšlel nad tím, proč Java spotřebuje nutně na každou blokující operaci jeden thread.
Vyhoda pri blokujucom volani je, ze OS za teba automaticky riesi backpressure. Napr. rychlo pisuce thready sa blocknu dokym consumeri nestihaju.

Nevyhoda je, ze potrebujes dodat nejake vlakno na zablokovanie, ktore nieco stoji a (zjednodusene povedane) pri 10K vlaknach to uz nefunguje tak dobre, hlavne pri sietovom IO.

Nad rotacnym diskom alebo paskovou mechanikou asi nebudes mat 10K threadov robiacich random IO subezne. Tam ziskas najviac, ked znizis contention na minimum, povedzme trebars 1 thread a je ti teda jedno, ze citas blokujuco, kedze vies, ze zariadenie primarne obhospodaruje iba teba a si sam.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 31. 07. 2018, 09:56:52
Ještě by to chtělo nějaký benchmark, kde výstupem bude graf závislosti doby zpracování requestu na počtu vytvořených threadů.

Představoval bych si to tak, že udělám Server, který bude na obyč socketu naslouchat. Thread poolu nastavím fixně 2000 threadů. Každému requestu dá z poolu 1 thread. Ten thread na 6000ms uspí a potom odepíše OK, takže ten thread nebude vlastně celou dobu nic dělat. Potom porovnám dobu zpracování toho requstu minus 6000ms a bude mě zajímat, jak roste doba obsloužení 1 requestu s rostoucím počtem spících threadů.

Ve smyčce bych dal každých 3ms vytvořit z threadpoolu thread pro 1 request přes socket, takže za těch 6000ms by to mělo udělat celkem necelých 2000 threadů.

Akorát problém tady je, že ten Thread.sleep() úplně nepředstavuje správnou blokující operaci. Nebo jo? To si obsluhuje Java předpokládám, kdy má který thread probudit.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: mhi_ 31. 07. 2018, 14:07:19
http://www.boa.org/ tady mate nonblocking single-thread server, ktery slouzi jako dobry priklad jak to napsat bez knihoven.

Mam za to, ze dobre napsany automat bude vzdy rychlejsi, nez multithreadovy server. Zasadni problem, na ktery se dnes narazi jsou SMP a load-balancing jednotlivych threadu resicich to same aby vytizily vsechna CPU.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 14:23:59
Ještě by to chtělo nějaký benchmark, kde výstupem bude graf závislosti doby zpracování requestu na počtu vytvořených threadů.

Představoval bych si to tak, že udělám Server, který bude na obyč socketu naslouchat. Thread poolu nastavím fixně 2000 threadů. Každému requestu dá z poolu 1 thread. Ten thread na 6000ms uspí a potom odepíše OK, takže ten thread nebude vlastně celou dobu nic dělat. Potom porovnám dobu zpracování toho requstu minus 6000ms a bude mě zajímat, jak roste doba obsloužení 1 requestu s rostoucím počtem spících threadů.

Ve smyčce bych dal každých 3ms vytvořit z threadpoolu thread pro 1 request přes socket, takže za těch 6000ms by to mělo udělat celkem necelých 2000 threadů.

Akorát problém tady je, že ten Thread.sleep() úplně nepředstavuje správnou blokující operaci. Nebo jo? To si obsluhuje Java předpokládám, kdy má který thread probudit.

nejde o rychlost, ale o škálovatelnost. Zátěž při přidávání vláken neroste lineárně. Do určitého počtu vláken bude ten thread pool stejně rychlý, možná i rychlejší. Ale co když tu aplikaci bude používat víc než 2000 uživatelů současně? Zatím tu nezazněl jediný argument proti neblokujícímu IO. Děláš raketovou vědu z něčeho, co lze napsat na 3 řádky tak, že to obslouží 2 miliony spojení.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: Ivan 31. 07. 2018, 14:45:55
Zrovna jsem přemýšlel nad tím, proč Java spotřebuje nutně na každou blokující operaci jeden thread.

Je porad jeste pravda? Drivejsi JVM API nemelo neco jako epoll, ale tohle uz IMHO neplati.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: xxx 31. 07. 2018, 14:53:34
Java NIO, Selektory
https://docs.oracle.com/javase/7/docs/api/java/nio/channels/package-summary.html (https://docs.oracle.com/javase/7/docs/api/java/nio/channels/package-summary.html)
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: Jirsák 31. 07. 2018, 15:06:29
Jirsák je zde!
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: borekz 31. 07. 2018, 15:55:13
s proměnnou s pracujete stejně jako se souborem, jen před blokující operace přidáte await a před for smyčku dáte async. Žádná věda.
To je ale v podstatě vlákno, jen je to řešené na úrovni jazyka místo operačního systému a ne všechny jazyky to umí.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 31. 07. 2018, 17:49:13
Coz me privadi k otazce jak funguje projekt Quasar, protoze ten sice umi delat fibery, ale kdyz vlakno spadne do blokujici operace v nativním kódu, třeba u jdbc, tak proste Quasar nemuze podle me delat proste nic. Nebo muze? Proste 1 blokujici operace v nativním kódu = 1 thread. Muze udelat maximalne to, ze tu situaci detekuje a vytvori nove vlakno, aby mohl dal multitaskovat mezi fibery.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 18:30:00
s proměnnou s pracujete stejně jako se souborem, jen před blokující operace přidáte await a před for smyčku dáte async. Žádná věda.
To je ale v podstatě vlákno, jen je to řešené na úrovni jazyka místo operačního systému a ne všechny jazyky to umí.

je to abstrakce nad neblokujícím IO. Nějakou formu kooperativního multitaskingu umí všechny jazyky. Z principu je to jednodušší než vlákna.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 18:41:39
Coz me privadi k otazce jak funguje projekt Quasar, protoze ten sice umi delat fibery, ale kdyz vlakno spadne do blokujici operace v nativním kódu, třeba u jdbc, tak proste Quasar nemuze podle me delat proste nic. Nebo muze? Proste 1 blokujici operace v nativním kódu = 1 thread. Muze udelat maximalne to, ze tu situaci detekuje a vytvori nove vlakno, aby mohl dal multitaskovat mezi fibery.

pokud potřebuješ používat nějakou blokující knihovnu, tak se to řeší tak, že blokující operace spustíš v thread poolu.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 18:59:39
Coz me privadi k otazce jak funguje projekt Quasar, protoze ten sice umi delat fibery, ale kdyz vlakno spadne do blokujici operace v nativním kódu, třeba u jdbc, tak proste Quasar nemuze podle me delat proste nic. Nebo muze? Proste 1 blokujici operace v nativním kódu = 1 thread. Muze udelat maximalne to, ze tu situaci detekuje a vytvori nove vlakno, aby mohl dal multitaskovat mezi fibery.

pokud potřebuješ používat nějakou blokující knihovnu, tak se to řeší tak, že blokující operace spustíš v thread poolu.

konkrétně ten Quasar framework má metodu runBlocking, které předáš jako první parametr thread pool.

https://docs.paralleluniverse.co/quasar/javadoc/co/paralleluniverse/fibers/FiberAsync.html#runBlocking(java.util.concurrent.ExecutorService,%20co.paralleluniverse.common.util.CheckedCallable)
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 31. 07. 2018, 19:06:46
Coz me privadi k otazce jak funguje projekt Quasar, protoze ten sice umi delat fibery, ale kdyz vlakno spadne do blokujici operace v nativním kódu, třeba u jdbc, tak proste Quasar nemuze podle me delat proste nic. Nebo muze? Proste 1 blokujici operace v nativním kódu = 1 thread. Muze udelat maximalne to, ze tu situaci detekuje a vytvori nove vlakno, aby mohl dal multitaskovat mezi fibery.

pokud potřebuješ používat nějakou blokující knihovnu, tak se to řeší tak, že blokující operace spustíš v thread poolu.

konkrétně ten Quasar framework má metodu runBlocking, které předáš jako první parametr thread pool.

https://docs.paralleluniverse.co/quasar/javadoc/co/paralleluniverse/fibers/FiberAsync.html#runBlocking(java.util.concurrent.ExecutorService,%20co.paralleluniverse.common.util.CheckedCallable)

Haha, no to jsem si myslel. Takže v tom případě je Quasar k čemu? Quasar nechceš na paralelní výpočty, ale když už, tak na blokující operace. Jenže k čemu ti to je, když to stejně potřebuje thread pool. To jsi zase na začátku, 1 thread 1 blokující operace. A v momentě, když bych měl asynchronní JDBC, tak na co mi je quasar? Vždyť to si raději udělám 1 thread co bude volat ve smyčcce Available() nad všema JDBC dotazama, na to zase nepotřebuju Quasar. Resp. nebudu si to dělat já, ale určitě vzniknou ConnectionPooly které to takto budou umět.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 31. 07. 2018, 19:10:32
Prostě dokud nebude asynchronní JDBC, tak tohle všechno ohledně Threadů můžu pustit tak akorát z hlavy, protože 1 JDBC query 1 thread no matter what, s quasarem či bez něj. Takže si můžu dál z vesela používat Tomcat a staré Servlety, co dělají 1 thread per request.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 19:15:39
Coz me privadi k otazce jak funguje projekt Quasar, protoze ten sice umi delat fibery, ale kdyz vlakno spadne do blokujici operace v nativním kódu, třeba u jdbc, tak proste Quasar nemuze podle me delat proste nic. Nebo muze? Proste 1 blokujici operace v nativním kódu = 1 thread. Muze udelat maximalne to, ze tu situaci detekuje a vytvori nove vlakno, aby mohl dal multitaskovat mezi fibery.

pokud potřebuješ používat nějakou blokující knihovnu, tak se to řeší tak, že blokující operace spustíš v thread poolu.

konkrétně ten Quasar framework má metodu runBlocking, které předáš jako první parametr thread pool.

https://docs.paralleluniverse.co/quasar/javadoc/co/paralleluniverse/fibers/FiberAsync.html#runBlocking(java.util.concurrent.ExecutorService,%20co.paralleluniverse.common.util.CheckedCallable)

Haha, no to jsem si myslel. Takže v tom případě je Quasar k čemu? Quasar nechceš na paralelní výpočty, ale když už, tak na blokující operace. Jenže k čemu ti to je, když to stejně potřebuje thread pool. To jsi zase na začátku, 1 thread 1 blokující operace. A v momentě, když bych měl asynchronní JDBC, tak na co mi je quasar? Vždyť to si raději udělám 1 thread co bude volat ve smyčcce Available() nad všema JDBC dotazama, na to zase nepotřebuju Quasar. Resp. nebudu si to dělat já, ale určitě vzniknou ConnectionPooly které to takto budou umět.

je rozdíl mezi socketovým spojením, které trvá hodiny. A databázovým dotazem/souborovou operací/http requestem, které trvají zlomek sekundy. Jestli ti vadí blokující legacy knihovny, tak přejdi na javascript, kde je vše navenek neblokující (i když vnitřně pro některé operace vlákna používá).
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 19:19:54
Prostě dokud nebude asynchronní JDBC, tak tohle všechno ohledně Threadů můžu pustit tak akorát z hlavy, protože 1 JDBC query 1 thread no matter what, s quasarem či bez něj. Takže si můžu dál z vesela používat Tomcat a staré Servlety, co dělají 1 thread per request.

databázový server stejně spouští dotazy ve vláknech. S 1 thread per request narazíš jakmile začneš používat websockety, long pooling a podobně.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 20:14:43
Vždyť to si raději udělám 1 thread co bude volat ve smyčcce Available() nad všema JDBC dotazama, na to zase nepotřebuju Quasar.

Ta smyčka by ti zablokovala zbytek aplikace. Jestli se chceš naučit moderní aynchronní programování, doporučuji Javascript. Quasar má neskutečně ošklivé API.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 31. 07. 2018, 21:48:31
No, asi z trochu jiného pohledu, Windows mi žerou zvesela 1500 threadů průběžně. Podle stackoverflow

https://stackoverflow.com/questions/373098/whats-the-average-requests-per-second-for-a-production-web-application

Wikipedie měla 100-200 requestů za vteřinu na 1 server. To se dá v pohodě utáhnout stylem 1 request/1 thread, na to nepotřebuju vymýšlet Quasary a Javascripty. I bych mohl klidně z poolu mít udělaných na každý request 10 threadů, takže až 2000 threadů, to PC s Linuxem musí úplně v pohodě zvládnout.

Já jsem zkoušel udělat si 15000 spících threadů a systém to nijak nevytěžuje. Dokonce ani není pravda očividně to, že 1 thread = 1 mb v RAM, to ani náhodou neodpovídalo realitě, spíše mi to přijde jako nanejvýš třetinová hodnota.

Takže asi to v praxi nebude s tím bezthreadovým async zase tak horké. Takže let's go na JDBC a Servlety, tohle je jen takový hype bez kterého se svět nezblázní.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 31. 07. 2018, 22:04:35
A tady je výsledek měření. Měl jsem Socket server, které každému připojení udělal Thread a nechal ho čekat 100 vteřin. Potom odeslal "OK" a socket i thread ukončil.

Client vytvářel sockety , připojující se na server každých 5ms. Výsledek dole Threads znamená, kolik vlastně chrápalo na serveru paralelně thradů s připojenými sockety.

Jen ještě upozorňuju, že počet vytvořených Threadů je dvojnásobný: jedenkrát za client sockety a jedenkrát za server accepty.

Threads 100 time 1
Threads 200 time 1
Threads 400 time 1
Threads 800 time 1
Threads 1600 time 0
Threads 3200 time 0
Threads 6400 time 0

Výsledek je, že zde není naprosto žádný overhaul kvůli vysokému množství threadů. Ty thready prostě chrápou a basta, a potom začnou každých 5ms odpovídat "OK".
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 22:09:42
No, asi z trochu jiného pohledu, Windows mi žerou zvesela 1500 threadů průběžně. Podle stackoverflow

https://stackoverflow.com/questions/373098/whats-the-average-requests-per-second-for-a-production-web-application

Wikipedie měla 100-200 requestů za vteřinu na 1 server. To se dá v pohodě utáhnout stylem 1 request/1 thread, na to nepotřebuju vymýšlet Quasary a Javascripty. I bych mohl klidně z poolu mít udělaných na každý request 10 threadů, takže až 2000 threadů, to PC s Linuxem musí úplně v pohodě zvládnout.

Já jsem zkoušel udělat si 15000 spících threadů a systém to nijak nevytěžuje. Dokonce ani není pravda očividně to, že 1 thread = 1 mb v RAM, to ani náhodou neodpovídalo realitě, spíše mi to přijde jako nanejvýš třetinová hodnota.

Takže asi to v praxi nebude s tím bezthreadovým async zase tak horké. Takže let's go na JDBC a Servlety, tohle je jen takový hype bez kterého se svět nezblázní.

bavíme se o socketových spojeních nebo o requestech? 100-200 requestů za vteřinu může být klidně 100 tisíc uživatelů s otevřenou wikipedií. Pokud využíváš websockety jen pro nějakou okrajovou funkcionalitu, jako např. notifikace, tak nevím, proč by to mělo žrát polovinu výkonu a paměti serveru.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: Vysvetlitel 31. 07. 2018, 22:10:31
Povim ti, proc tak banalni operace a tolik otazek a debat kolem toho. Koukas na vysledek abstraction leaku v unixu. Spatnej design proste. Lidi tady bud obhajujou, ze lip to napsat neslo nebo
 ochcavky jako epoll prezentujou jako nejaky super reseni, pritom je to akorat hozeni rucniku do ringu a mas si to vyresit low level sam.

Podobna ochcavka je predani callbacku. Ztratis tim traceback a udelas si z kodu spagety. To mohli rovnou nechat goto protoze callbacky jsou prakticky totez.

Jiny reseni je vyhodit planovac vlaken operacniho systemu do rite a udelat si ho v programovacim jazyce znova. Viz async knihovny, Go, apod.

Je doufam poznat ze je to akorat sada hacku jeden za druhym.

Problem je v tom ze 'nemuzes' pouzivat libovolne vlaken, protoze jsou tezkopadny. To je ta designova chyba, protoze tezkopadny bejt vubec nemusi. Viz Go a async v ruznych jazycich. Vlakno by mela bejt absrakce na urovni treba funkce. Dokazes si predstavit, ze muzes pouzit treba jenom 10 funkci na program, protoze to tehdy nejaky jelito zprasilo v designu OS a udelalo je tezkopadny, jen aby to bylo o chlup rychlejsi?

Kdyby to nekoho zajimalo tak chyba je v zakladni datovy strukture vlaken - stacku. Mel se pouzit stack stacku aka cactus stack, kdy jednoduse vyhodis kus stacku do padous a nahradis ho jinym kdyz menis vlakna v planovaci. Vysledkem jsou delimited continuations, ale to je mimo scope teto lekce.

Aspon by mohli ve skolach zminit ze design unixu je deravej shit at si lidi nemysli jaky jsou bedny kdyz ho nauci pouzivat.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 22:11:13
A tady je výsledek měření. Měl jsem Socket server, které každému připojení udělal Thread a nechal ho čekat 100 vteřin. Potom odeslal "OK" a socket i thread ukončil.

Client vytvářel sockety , připojující se na server každých 5ms. Výsledek dole Threads znamená, kolik vlastně chrápalo na serveru paralelně thradů s připojenými sockety.

Jen ještě upozorňuju, že počet vytvořených Threadů je dvojnásobný: jedenkrát za client sockety a jedenkrát za server accepty.

Threads 100 time 1
Threads 200 time 1
Threads 400 time 1
Threads 800 time 1
Threads 1600 time 0
Threads 3200 time 0
Threads 6400 time 0

Výsledek je, že zde není naprosto žádný overhaul kvůli vysokému množství threadů. Ty thready prostě chrápou a basta, a potom začnou každých 5ms odpovídat "OK".

postni sem kód.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 31. 07. 2018, 22:14:16
Podobna ochcavka je predani callbacku.

což nikdo normální dávno nepoužívá.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 31. 07. 2018, 22:20:11
Kód: [Vybrat]
@RunWith(JUnit4.class)
public class Play {

    private static final long RESPONSE_DELAY = 100000;
    AtomicLong count = new AtomicLong(0);
    AtomicLong sumTime = new AtomicLong(0);


    class SocketRespond implements Runnable {
        private final Socket socket;

        public SocketRespond(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try (OutputStream os = socket.getOutputStream()) {
                OutputStreamWriter w = new OutputStreamWriter(os);
                PrintWriter p = new PrintWriter(w);
                Thread.sleep(RESPONSE_DELAY);
                p.println("OK");
                p.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class ServerListener implements Runnable {
        ServerSocket serverSocket;

        @Override
        public void run() {
            try {
                serverSocket = new ServerSocket(6666);
                out.println("Srv start");
                while (true) {
                    Socket newConnection = serverSocket.accept();
                    Thread t = new Thread(new SocketRespond(newConnection));
                    t.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void start() throws IOException, InterruptedException, ExecutionException {
        Thread serverThread = new Thread(new ServerListener());
        serverThread.start();

        Thread.sleep(300);

       
        for(int i = 100; i< 10000; i*=2) {
            List<Thread> threads = new ArrayList<>();
            for(int j = 0; j < i; j++) {
                Thread sockTh = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            connect();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
                Thread.sleep(5);
                threads.add(sockTh);
                sockTh.start();
            }

            for(Thread t2 : threads) {
                t2.join();
            }

            out.println("Threads " + i + " time " + sumTime.get() / count.get());
            sumTime.set(0);
            count.set(0);
            threads.clear();
        }


    }
   
    public void connect() throws IOException {
        long timer = System.currentTimeMillis();
        Socket s = new Socket("127.0.0.1", 6666);
        BufferedReader b = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str = b.readLine();
        timer = System.currentTimeMillis() - timer;

        Assert.assertEquals(str, "OK");

        count.incrementAndGet();
        sumTime.addAndGet(timer - RESPONSE_DELAY);
        b.close();
        s.close();
    }
}
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: bejk 01. 08. 2018, 08:58:23
Podobna ochcavka je predani callbacku.

což nikdo normální dávno nepoužívá.

signal handlery, javascript
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: MarSik 01. 08. 2018, 10:27:24
Kdyby to nekoho zajimalo tak chyba je v zakladni datovy strukture vlaken - stacku. Mel se pouzit stack stacku aka cactus stack, kdy jednoduse vyhodis kus stacku do padous a nahradis ho jinym kdyz menis vlakna v planovaci. Vysledkem jsou delimited continuations, ale to je mimo scope teto lekce.

Což bude fungovat pro případ, kdy všechna ta lehká vlákna běží na jednom CPU. Jenže dneska máme i mašiny s pár stovkami jader. A pro plný paralelismus je potřeba mít pro každé to vlákno i paměťově nezávislý stack.

Takže ideální stav pro plné vytížení N CPU je naopak N těžkých posix vláken a interní plánovač co rozděluje lehká vlákna ke zpracování těm posixovým.

Aspon by mohli ve skolach zminit ze design unixu je deravej shit at si lidi nemysli jaky jsou bedny kdyz ho nauci pouzivat.

A vy si prosím uvědomte, že ne každý ho používá na desktopu s minimem jader.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: MarSik 01. 08. 2018, 10:30:26
Podobna ochcavka je predani callbacku.

což nikdo normální dávno nepoužívá.

V browseru si klidně používejte Promises nebo PubSub. Já si to na jednojádrovém mikrokontroleru s 8 kiB RAM dovolit nemůžu. Stejně je to jen syntaktický cukr, který obaluje interně připravenou callback funkci.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: backup 01. 08. 2018, 10:31:57
Kdyby to nekoho zajimalo tak chyba je v zakladni datovy strukture vlaken - stacku. ..

Aspon by mohli ve skolach zminit ze design unixu je deravej shit ...

v návrhu unixu byla vlákna?
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 01. 08. 2018, 13:25:43
javascript

V browseru si klidně používejte Promises nebo PubSub. Já si to na jednojádrovém mikrokontroleru s 8 kiB RAM dovolit nemůžu. Stejně je to jen syntaktický cukr, který obaluje interně připravenou callback funkci.


javascript má coroutiny. Mikrokontrolery bych do diskuze vlákna vs. non-blocking IO nezatahoval.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 01. 08. 2018, 13:29:13
Kód: [Vybrat]
@RunWith(JUnit4.class)
public class Play {

    private static final long RESPONSE_DELAY = 100000;
    AtomicLong count = new AtomicLong(0);
    AtomicLong sumTime = new AtomicLong(0);


    class SocketRespond implements Runnable {
        private final Socket socket;

        public SocketRespond(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try (OutputStream os = socket.getOutputStream()) {
                OutputStreamWriter w = new OutputStreamWriter(os);
                PrintWriter p = new PrintWriter(w);
                Thread.sleep(RESPONSE_DELAY);
                p.println("OK");
                p.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class ServerListener implements Runnable {
        ServerSocket serverSocket;

        @Override
        public void run() {
            try {
                serverSocket = new ServerSocket(6666);
                out.println("Srv start");
                while (true) {
                    Socket newConnection = serverSocket.accept();
                    Thread t = new Thread(new SocketRespond(newConnection));
                    t.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void start() throws IOException, InterruptedException, ExecutionException {
        Thread serverThread = new Thread(new ServerListener());
        serverThread.start();

        Thread.sleep(300);

       
        for(int i = 100; i< 10000; i*=2) {
            List<Thread> threads = new ArrayList<>();
            for(int j = 0; j < i; j++) {
                Thread sockTh = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            connect();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
                Thread.sleep(5);
                threads.add(sockTh);
                sockTh.start();
            }

            for(Thread t2 : threads) {
                t2.join();
            }

            out.println("Threads " + i + " time " + sumTime.get() / count.get());
            sumTime.set(0);
            count.set(0);
            threads.clear();
        }


    }
   
    public void connect() throws IOException {
        long timer = System.currentTimeMillis();
        Socket s = new Socket("127.0.0.1", 6666);
        BufferedReader b = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str = b.readLine();
        timer = System.currentTimeMillis() - timer;

        Assert.assertEquals(str, "OK");

        count.incrementAndGet();
        sumTime.addAndGet(timer - RESPONSE_DELAY);
        b.close();
        s.close();
    }
}

bez vláken by to bylo o 80% procent kratší a zvládlo by to 100x víc spojení.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: MarSik 01. 08. 2018, 14:07:58
bez vláken by to bylo o 80% procent kratší a zvládlo by to 100x víc spojení.

S vlákny taky, jen je potřeba to napsat správně. Dělat a spravovat si v Javě vlákna ručně je nesmysl už hodně let..

Použijte třeba cached thread pool a úlohy do něj posílejte. Nové vlákno se tím vytvoří dle potřeby a stará vlákna se znovupoužijí nebo ukončí podle zátěže.

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#submit-java.lang.Runnable-
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 01. 08. 2018, 14:11:37
bez vláken by to bylo o 80% procent kratší a zvládlo by to 100x víc spojení.

S vlákny taky, jen je potřeba to napsat správně. Dělat a spravovat si v Javě vlákna ručně je nesmysl už hodně let..

Použijte třeba cached thread pool a úlohy do něj posílejte. Nové vlákno se tím vytvoří dle potřeby a stará vlákna se znovupoužijí nebo ukončí podle zátěže.

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#submit-java.lang.Runnable-

thread pool je pro dlouhotrvající spojení nesmysl. Potřebujete jedno vlákno na spojení.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 01. 08. 2018, 14:51:36
Kód: [Vybrat]
@RunWith(JUnit4.class)
public class Play {

    private static final long RESPONSE_DELAY = 100000;
    AtomicLong count = new AtomicLong(0);
    AtomicLong sumTime = new AtomicLong(0);


    class SocketRespond implements Runnable {
        private final Socket socket;

        public SocketRespond(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try (OutputStream os = socket.getOutputStream()) {
                OutputStreamWriter w = new OutputStreamWriter(os);
                PrintWriter p = new PrintWriter(w);
                Thread.sleep(RESPONSE_DELAY);
                p.println("OK");
                p.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class ServerListener implements Runnable {
        ServerSocket serverSocket;

        @Override
        public void run() {
            try {
                serverSocket = new ServerSocket(6666);
                out.println("Srv start");
                while (true) {
                    Socket newConnection = serverSocket.accept();
                    Thread t = new Thread(new SocketRespond(newConnection));
                    t.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void start() throws IOException, InterruptedException, ExecutionException {
        Thread serverThread = new Thread(new ServerListener());
        serverThread.start();

        Thread.sleep(300);

       
        for(int i = 100; i< 10000; i*=2) {
            List<Thread> threads = new ArrayList<>();
            for(int j = 0; j < i; j++) {
                Thread sockTh = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            connect();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
                Thread.sleep(5);
                threads.add(sockTh);
                sockTh.start();
            }

            for(Thread t2 : threads) {
                t2.join();
            }

            out.println("Threads " + i + " time " + sumTime.get() / count.get());
            sumTime.set(0);
            count.set(0);
            threads.clear();
        }


    }
   
    public void connect() throws IOException {
        long timer = System.currentTimeMillis();
        Socket s = new Socket("127.0.0.1", 6666);
        BufferedReader b = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str = b.readLine();
        timer = System.currentTimeMillis() - timer;

        Assert.assertEquals(str, "OK");

        count.incrementAndGet();
        sumTime.addAndGet(timer - RESPONSE_DELAY);
        b.close();
        s.close();
    }
}

bez vláken by to bylo o 80% procent kratší a zvládlo by to 100x víc spojení.

Kdo říká že nemůžu dělat async s Feature nad vlákny. Vypadalo by to kompletně stejně, ať už pod tím byly vlákna nebo fibery.

A těch 100x více spojení bych měl k čemu? Tisícovky spojení vám nestačí?  Na takovou webovou službu, kde máte tolik spojení, už si snad vyhradíte samostatný server, protože to poslední co řešíte je pár tisícovek za PC. A pokud bych na to něco opravdu potřeboval 100x více spojení, tak to by byla nějaká supervýkonná lehká služba a na to zase se můžu vyprdnout rovnou na Javascript, to už snad udělám tuhle věc raději nějak v C/C++ ne?

Tady podle mě to v te Javě není zase tak špatné, když nebudu odříznutý od reality tak je to dostačující pro 95% usecase na trhu práce.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: y, 01. 08. 2018, 14:59:53
Ad to preruseni v puvodnim dotazu -- nemam zkusenosti s Arduinem, ale v rade operacnich systemu je cas, ktery jde stravit obsluhou preruseni pomerne omezeny (obsluha bezi na vyssi urovni opravneni, neni prerusitelna...).
Z tohoto pohledu dava smysl a) neobtezovat programatora technickymi detaily obsluhy preruseni a take b) neduverovat, ze by to provedl spravne. Cili obsluha preruseni nalezi systemu, ten ukonci cekani danych soketu a ma hotovo.

b) proc to neni delano jinak? Protoze ten interface je uz nekolik desitek let stary a asi v te dobe daval designerum smysl, i v ohledu na implementacni narocnost, platformovou nezavislost a pozadavky na zdroje.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 01. 08. 2018, 15:24:56
Kdo říká že nemůžu dělat async s Feature nad vlákny. Vypadalo by to kompletně stejně, ať už pod tím byly vlákna nebo fibery.

A těch 100x více spojení bych měl k čemu? Tisícovky spojení vám nestačí?  Na takovou webovou službu, kde máte tolik spojení, už si snad vyhradíte samostatný server, protože to poslední co řešíte je pár tisícovek za PC. A pokud bych na to něco opravdu potřeboval 100x více spojení, tak to by byla nějaká supervýkonná lehká služba a na to zase se můžu vyprdnout rovnou na Javascript, to už snad udělám tuhle věc raději nějak v C/C++ ne?

Tady podle mě to v te Javě není zase tak špatné, když nebudu odříznutý od reality tak je to dostačující pro 95% usecase na trhu práce.

klidně to naprogramuj v assembleru. Stále to bude řádově nenažranější než javascriptový event loop.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: MarSik 01. 08. 2018, 16:15:55
thread pool je pro dlouhotrvající spojení nesmysl. Potřebujete jedno vlákno na spojení.

Že vy jste tu dokumentaci nečetl...

Citace
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available.

cached thread pool právě umí pustit nové vlákno, stejně jako umí znovupoužít staré vlákno a tím snížit režii. Těch dlouhotrvajících spojení zase obvykle tolik není. Pokud tedy řešíme 10M tak stejně narazíte na limit počtu otevřených file deskriptorů a vlákna budou ten menší problém.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: MarSik 01. 08. 2018, 16:18:46
klidně to naprogramuj v assembleru. Stále to bude řádově nenažranější než javascriptový event loop.

Ale poběží to paralelně (parallel), ne jen ve stejném čase (concurrent). Javascriptová event smyčka v browseru i nodejs je pokud vím jednovláknová.

Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: anonym 01. 08. 2018, 20:21:53
Kdo říká že nemůžu dělat async s Feature nad vlákny. Vypadalo by to kompletně stejně, ať už pod tím byly vlákna nebo fibery.

A těch 100x více spojení bych měl k čemu? Tisícovky spojení vám nestačí?  Na takovou webovou službu, kde máte tolik spojení, už si snad vyhradíte samostatný server, protože to poslední co řešíte je pár tisícovek za PC. A pokud bych na to něco opravdu potřeboval 100x více spojení, tak to by byla nějaká supervýkonná lehká služba a na to zase se můžu vyprdnout rovnou na Javascript, to už snad udělám tuhle věc raději nějak v C/C++ ne?

Tady podle mě to v te Javě není zase tak špatné, když nebudu odříznutý od reality tak je to dostačující pro 95% usecase na trhu práce.

klidně to naprogramuj v assembleru. Stále to bude řádově nenažranější než javascriptový event loop.

NJ, jenže ten jednovláknové event loop je i v javě, jen už na to nemůžu použít jdbc. Java má i asynchronní sockety, ale asynchronní jdbc se teprve dělá. Můžu použít ale asynchronní Driver, třeba PostgreSQL ho má, ale není to jdbc. Takže jen jsem chtěl říct, že pořád to raději udělám v javě než v JS.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 01. 08. 2018, 21:09:07
NJ, jenže ten jednovláknové event loop je i v javě, jen už na to nemůžu použít jdbc. Java má i asynchronní sockety, ale asynchronní jdbc se teprve dělá. Můžu použít ale asynchronní Driver, třeba PostgreSQL ho má, ale není to jdbc. Takže jen jsem chtěl říct, že pořád to raději udělám v javě než v JS.

existuje

http://docs.paralleluniverse.co/comsat/#db-access

vnitřně to používá runBlocking. Ani to jinak nejde, vždy se připojuješ přes nějaký omezený connection pool. Stále nechápeš, že nikdy nebude spuštěno 10k sql dotazů současně, ale 10k websocketových spojení není scifi.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 01. 08. 2018, 21:13:59
Pokud tedy řešíme 10M tak stejně narazíte na limit počtu otevřených file deskriptorů a vlákna budou ten menší problém.

10M je asi moc, ale půl milionu jde.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: kimec 01. 08. 2018, 22:10:53
NJ, jenže ten jednovláknové event loop je i v javě, jen už na to nemůžu použít jdbc. Java má i asynchronní sockety, ale asynchronní jdbc se teprve dělá. Můžu použít ale asynchronní Driver, třeba PostgreSQL ho má, ale není to jdbc. Takže jen jsem chtěl říct, že pořád to raději udělám v javě než v JS.

existuje

http://docs.paralleluniverse.co/comsat/#db-access

vnitřně to používá runBlocking. Ani to jinak nejde, vždy se připojuješ přes nějaký omezený connection pool. Stále nechápeš, že nikdy nebude spuštěno 10k sql dotazů současně, ale 10k websocketových spojení není scifi.
Nie som si isty, ci rozumiete tomu, co napisal anonym. Riesenie od Quasar/COMSAT pouziva blokujuce API a nie je mozne sa v nom hooknut do jednovlaknoveho eventloopu. runBlocking nie je problem connection poolu, ale toho, ze JDBC je blokujuce API. Mozete mat datasource aj bez connection poolu s jednym spojenim a nic to nezmeni na tom, ze JDBC je blokujuce API a bude nutne volat runBlocking a stale sa nebudete vediet hooknut do toho eventloopu.

Ako anonym spravne napisal, k PostgreSQL existuju najmenej 2 non blocking drivery postavene na Netty, ale povedal by  som, ze len tak tak ziju.

Anonym by bol urobil lepsie, keby namiesto privlastku async pouzil non-blocking. Async operacie sa mozu robit aj nad blokujucimi API a threadpoolom - vid. COMSAT JDBC. eventloop s non-blocking IO je trosicku ina vec. Kazdopadne, oboje sa v Jave robit da. Ten druhy case, t.j. eventloop s non-blocking IO, sa o chvilu stane main stream, kedze ho zacal tlacit Spring 5 WebFlux a reactive data (ktore logicky nezahrnaju JDBC).
Preto predpokladam, ze atraktivita node.js pre Javistov, aspon pre tento use case, este viac.

10k websocketovych spojeni je z hladiska procesoroveho casu vascinu casu neaktivnych, kedze IO trva vecnost. Nechapem co ich robi viac ne-scifi ako 10k sql dotazov.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: gll 01. 08. 2018, 23:11:08
runBlocking nie je problem connection poolu, ale toho, ze JDBC je blokujuce API. Mozete mat datasource aj bez connection poolu s jednym spojenim a nic to nezmeni na tom, ze JDBC je blokujuce API a bude nutne volat runBlocking a stale sa nebudete vediet hooknut do toho eventloopu.

runBlocking právě nezablokuje vlákno event loopu. Spustí blokující kód ve vlákně thread poolu a výsledek zpracujete v callbacku. Nebo přeruší coroutinu. Nevím, jaké abstrakce ten framework podporuje. Každopádně to slouží k volání blokujícího kódu mimo event loop.

10k websocketovych spojeni je z hladiska procesoroveho casu vascinu casu neaktivnych, kedze IO trva vecnost. Nechapem co ich robi viac ne-scifi ako 10k sql dotazov.

máte 10k aktivních uživatelů, kterým občas zašlete notifikaci. To je běžná situace například u zpravodajských webů. Na druhou stranu se nikdy nestane (nemělo by se stát), aby všichni najednou dotazovali databázi. Od toho máte cachování a i ten thread pool. Obsluha websocketů může být v odděleném procesu, který do DB nepřistupuje.
Název: Re:Proč je čtení ze Socketu blokjící operace?
Přispěvatel: kvr kvr 02. 08. 2018, 04:14:49
Problém není v zásadě klasická web aplikace, která je stejně ve výsledku synchronní. Typické použití asynchronního network IO je v IoT, případně v messaging (websocket) aplikacích. Tam se connection drží klidně minuty až hodiny a traffic je přitom minimální.

Vytvářet thread pro něco, co je většinu času mrtvé, je zcela zbytečné. Samotná cena za thread není tak velká, řekl bych, že OS je dokáže povětšinou ignorovat a paměťově je to kernel stack, user stack, skoro prázdný page table entry a nějaká malá struktura v kernelu - tedy řádově pár stránek paměti. Problém je ale context switch - když je třeba něco poslat, je třeba thread probudit, udělat skoro nic a zase uspat. I když jde o stejný proces, tak jde o obnovení registrů, postupné vyčerpání cache, TLB cache atd. Když pošlu broadcast na spoustu klientů, tak skoro nic umoří ... cokoliv.

Pro detaily viz C10k problem (http://"https://en.wikipedia.org/wiki/C10k_problem"), případně benchmark netty vs javascript (http://"https://mrekucci.blogspot.com/2014/09/asynchronous-io-micro-war.html").