Proč je čtení ze Socketu blokjící operace?

anonym

Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #45 kdy: 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.


y,

Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #46 kdy: 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.

gll

  • ****
  • 429
    • Zobrazit profil
    • E-mail
Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #47 kdy: 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.

MarSik

Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #48 kdy: 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.

MarSik

Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #49 kdy: 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á.



anonym

Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #50 kdy: 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.

gll

  • ****
  • 429
    • Zobrazit profil
    • E-mail
Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #51 kdy: 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.

gll

  • ****
  • 429
    • Zobrazit profil
    • E-mail
Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #52 kdy: 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.

kimec

Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #53 kdy: 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.

gll

  • ****
  • 429
    • Zobrazit profil
    • E-mail
Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #54 kdy: 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.

Re:Proč je čtení ze Socketu blokjící operace?
« Odpověď #55 kdy: 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, případně benchmark netty vs javascript.