Programovanie neblokujúcich I/O pomocou greenletov a v node.js
V dnešnom blogu sa pozrieme na dva rôzne spôsoby zápisu neblokujúcich I/O. Jeden bude použitím callback funkcií používaných v node.js a druhý pomocou greenletov v pyhtone.
Príklad
Náš ukážkový program bude veľmi jednoduchý. Náš program bude zobrazovať výrok dňa, ktorý bude uložený v memcache (kvôli jednoduchosti). Kontaktovať memcache budeme vždy 2x - prvým prístupom zistíme kľúč v ktorom je výrok uložený a druhým prístupom získame samotný výrok.
Node.js
// server.js var http = require('http'); var Memcached = require('memcached'); var memcached = new Memcached('127.0.0.1:11211'); // pripojenie na memcache // Nastavenie premenných, toto by mal riešiť externý skript memcached.set("msg_var", "vyrok_2013-07-12") memcached.set("vyrok_2013-07-12", "vyrok pre dnesok") http.createServer(function (req, res) { // IO operácia - načítanie msg var memcached.get('msg_var', function(err, msg_var) { // callback po načítaní msg_var if (err) { sys.puts('Error!'); return; } // IO operácia - načítanie konkrétneho výroku memcached.get(msg_var, function(err, msg) { if (err) { sys.puts('Error!'); return; } res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(msg); // výpis výroku }); }); }).listen(8888, '127.0.0.1');
Príklad sa spúšťa príkazom node server.js
. Pred spustením samozrejme musíme nainštalovať a spustiť memcached a nainštalovať npm modul príkazom npm install memcached
.
gevent
# server.py from gevent.wsgi import WSGIServer import umemcache as memcache mc = memcache.Client('127.0.0.1:11211') mc.connect() mc.set("msg_var", "vyrok_2013-07-12") mc.set("vyrok_2013-07-12", "vyrok pre dnesok") def application(environ, start_response): start_response("200 OK", [('Content-Type', 'text/plain')]) msg_var = mc.get("msg_var")[0] msg = mc.get(msg_var)[0] yield msg WSGIServer(('127.0.0.1', 8888), application, log=None).serve_forever()
Server sa spustí príkazom python server.py
. Závislosti ako gevent a umemcache musia byť samozrejme pred spustením nainštalované.
Výsledky
Oba servery boli testované príkazom ab2 -n 10000 -c 100 127.0.0.1:8888
.
Node:
Concurrency Level: 100 Time taken for tests: 16.881 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 1180000 bytes HTML transferred: 170000 bytes Requests per second: 592.38 [#/sec] (mean) Time per request: 168.811 [ms] (mean) Time per request: 1.688 [ms] (mean, across all concurrent requests) Transfer rate: 68.26 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 3.1 0 46 Processing: 20 168 65.8 179 413 Waiting: 19 168 65.7 179 412 Total: 65 168 65.9 179 413 Percentage of the requests served within a certain time (ms) 50% 179 66% 204 75% 216 80% 220 90% 254 95% 281 98% 303 99% 389 100% 413 (longest request)
Gevent:
Concurrency Level: 100 Time taken for tests: 19.746 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 1180000 bytes HTML transferred: 170000 bytes Requests per second: 506.42 [#/sec] (mean) Time per request: 197.464 [ms] (mean) Time per request: 1.975 [ms] (mean, across all concurrent requests) Transfer rate: 58.36 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 1.6 0 24 Processing: 16 196 13.9 197 219 Waiting: 15 196 13.9 197 219 Total: 32 196 12.7 198 219 Percentage of the requests served within a certain time (ms) 50% 198 66% 201 75% 203 80% 204 90% 207 95% 209 98% 211 99% 212 100% 219 (longest request)
Výsledok
Žiaden zázrak v podobe zdrvujúcej prehry geventu sa nekonal. Dobre implementovaný kooperatívny multitasking je prakticky ekvivalentný s eventloopom v node.js. Rozdiel je prakticky len v zápise. Kvôli katastrofálnemu zápisu príkazov v node.js vznikli knižnice ako async, v tomto prípade sú však neaplikovateľné. Node.js má samozrejme svoje výhody v podobe knižníc pripravených na async I/O, ale rovnaká funkcionalita sa dá dosiahnuť aj inými spôsobmi.
Pre pridávanie komentárov sa musíte prihlásiť.