Nire azken lan-elkarrizketa baten ondoren, harrituta geratu nintzen konturatu nintzen eskatu nuen enpresak Laravel erabiltzen ari zela, duela hamarkada bat gutxi gorabehera probatu nuen PHP esparrua. Garai hartako duina zen, baina teknologian eta modetan konstante bat baldin badago, estilo eta kontzeptuen etengabeko aldaketa eta birsortzea da. JavaScript programatzailea bazara, ziurrenik txiste zahar hau ezagutzen duzu
1. programatzailea: "Ez zait gustatzen'JavaScript marko berri hau!"
2. programatzailea: "Ez da kezkatu beharrik. Sei hilabete itxaron besterik ez dago eta beste bat egongo da ordezkatzeko!"
Jakin-minagatik, zaharrak eta berriak proban jartzen ditugunean zer gertatzen den zehatz-mehatz ikustea erabaki nuen. Jakina, web erreferentzi eta erreklamazioz beteta dago, eta horietatik ezagunena da ziurrenik TechEmpower Web Framework Benchmarks hemen . Hala ere, gaur ez dugu ezer ia ia konplikaturik egingo. Gauza politak eta sinpleak mantenduko ditugu biak, artikulu hau bihurtu ez dadin Gerra eta Bakea , eta irakurtzen amaitzean esna egoteko aukera apur bat izango duzula' Ohiko oharrak aplikatzen dira: baliteke honek zure makinan berdin ez funtzionatzea, software-bertsio ezberdinek errendimenduan eragina izan dezakete eta Schrรถdinger';katua aldi berean erdi bizirik eta erdi hilda zegoen katu zonbi bihurtu zen.
Proba honetarako, nire ordenagailu eramangarria erabiliko dut Manjaro Linux exekutatzen duen i5 txiki batekin armatuta hemen erakusten den moduan.
โฐโโค uname -a
Linux jimsredmi 5.10.174-1-MANJARO #1 SMP PREEMPT Tuesday Mar 21 11:15:28 UTC 2023 x86_64 GNU/Linux
โฐโโค cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 126
model name : Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz
stepping : 5
microcode : 0xb6
cpu MHz : 990.210
cache size : 6144 KB
Gure kodeak hiru zeregin erraz izango ditu eskaera bakoitzerako:
Zer nolako proba idiota da hori, galdetuko zenuke? Bada, orrialde honen sareko eskaerak aztertzen badituzu, sessionvars.js izeneko bat ikusiko duzu gauza bera egiten duena.
Ikusten duzu, web-orri modernoak izaki konplikatuak dira, eta zeregin ohikoenetako bat orrialde konplexuak cachean gordetzea da datu-basearen zerbitzarian gehiegizko karga saihesteko.
Erabiltzaile batek eskatzen duen bakoitzean orrialde konplexu bat berriro errendatzen badugu, segundoko 600 erabiltzaile inguru bakarrik zerbitzatuko ditugu.
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1/system/index.en.html
Running 10s test @ http://127.0.0.1/system/index.en.html
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 186.83ms 174.22ms 1.06s 81.16%
Req/Sec 166.11 58.84 414.00 71.89%
6213 requests in 10.02s, 49.35MB read
Requests/sec: 619.97
Transfer/sec: 4.92MB
Baina orrialde hau HTML fitxategi estatiko gisa gordetzen badugu eta Nginx-i erabiltzaileari leihotik azkar botatzen uzten badiogu, orduan 32.000 erabiltzaileri zerbitzatuko diegu segundoko, errendimendua 50 aldiz handituz.
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1/system/index.en.html
Running 10s test @ http://127.0.0.1/system/index.en.html
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.03ms 511.95us 6.87ms 68.10%
Req/Sec 8.20k 1.15k 28.55k 97.26%
327353 requests in 10.10s, 2.36GB read
Requests/sec: 32410.83
Transfer/sec: 238.99MB
Index.en.html estatikoa guztiontzat doan zatia da, eta erabiltzaileen arabera desberdinak diren zatiak soilik bidaltzen dira sessionvars.js-en. Honek datu-basearen karga murrizten du eta gure erabiltzaileentzako esperientzia hobea sortzen du, baina baita gure zerbitzariak berez lurrunduko dituen probabilitate kuantikoak murrizten ditu klingoien erasoan deformazio-nukleoaren haustura batean.
Esparru bakoitzeko itzultzen den kodeak baldintza sinple bat izango du: erakutsi erabiltzaileari orria zenbat aldiz freskatu duen "Kontua x da" esanez. Gauzak sinpleak izan daitezen, Redis ilaretatik, Kubernetes osagaietatik edo AWS Lambdatik urrun egongo gara oraingoz.
Erabiltzaile bakoitzaren saioaren datuak PostgreSQL datu-base batean gordeko dira.
Eta datu-baseko taula hau proba bakoitzaren aurretik moztu egingo da.
Sinplea baina eraginkorra da Paferaren leloa... denbora-lerro ilunenetik kanpo, hala ere...
Ados, orain azkenean eskuak zikintzen has gaitezke. Laravelen konfigurazioa saltatuko dugu, konpositore eta artisau mordo bat besterik ez baita. aginduak.
Lehenik eta behin, gure datu-basearen ezarpenak .env fitxategian konfiguratuko ditugu
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=sessiontest
DB_USERNAME=sessiontest
DB_PASSWORD=sessiontest
Ondoren, eskaera guztiak gure kontrolagailura bidaltzen dituen bidegabeko bide bakarra ezarriko dugu.
Route::fallback(SessionController::class);
Eta ezarri kontrolagailua zenbaketa bistaratzeko. Laravelek, lehenespenez, datu-basean gordetzen ditu saioak. Gainera, eskaintzen du session()
funtzioa gure saioko datuekin interfazea izateko, beraz, kode lerro pare bat izan ziren gure orria errendatzeko.
class SessionController extends Controller
{
public function __invoke(Request $request)
{
$count = session('count', 0);
$count += 1;
session(['count' => $count]);
return 'Count is ' . $count;
}
}
php-fpm eta Nginx konfiguratu ondoren, gure orrialdeak nahiko itxura ona du...
โฐโโค php -v
PHP 8.2.2 (cli) (built: Feb 1 2023 08:33:04) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.2, Copyright (c) Zend Technologies
with Xdebug v3.2.0, Copyright (c) 2002-2022, by Derick Rethans
โฐโโค sudo systemctl restart php-fpm
โฐโโค sudo systemctl restart nginx
Proben emaitzak benetan ikusi arte behintzat...
PHP/Laravel
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1
Running 10s test @ http://127.0.0.1
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.08s 546.33ms 1.96s 65.71%
Req/Sec 12.37 7.28 40.00 56.64%
211 requests in 10.03s, 177.21KB read
Socket errors: connect 0, read 0, write 0, timeout 176
Requests/sec: 21.04
Transfer/sec: 17.67KB
Ez, hori ez da akatsa. Gure proba-makinak orrialde konplexu bat errendatzen duen segundoko 600 eskaera izatetik... segundoko 21 eskaera izatera pasa da "zenbaketa 1 da".
Beraz, zer gertatu zen gaizki? Zerbait gaizki al dago gure PHP instalazioarekin? Nginx nolabait moteltzen al da php-fpm-rekin konektatzean?
Egin dezagun orri hau PHP kode hutsean.
<?php
// ====================================================================
function uuid4()
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
// ====================================================================
function Query($db, $query, $params = [])
{
$s = $db->prepare($query);
$s->setFetchMode(PDO::FETCH_ASSOC);
$s->execute(array_values($params));
return $s;
}
// ********************************************************************
session_start();
$sessionid = 0;
if (isset($_SESSION['sessionid']))
{
$sessionid = $_SESSION['sessionid'];
}
if (!$sessionid)
{
$sessionid = uuid4();
$_SESSION['sessionid'] = $sessionid;
}
$db = new PDO('pgsql:host=127.0.0.1 dbname=sessiontest user=sessiontest password=sessiontest');
$data = 0;
try
{
$result = Query(
$db,
'SELECT data FROM usersessions WHERE uid = ?',
[$sessionid]
)->fetchAll();
if ($result)
{
$data = json_decode($result[0]['data'], 1);
}
} catch (Exception $e)
{
echo $e;
Query(
$db,
'CREATE TABLE usersessions(
uid TEXT PRIMARY KEY,
data TEXT
)'
);
}
if (!$data)
{
$data = ['count' => 0];
}
$data['count']++;
if ($data['count'] == 1)
{
Query(
$db,
'INSERT INTO usersessions(uid, data)
VALUES(?, ?)',
[$sessionid, json_encode($data)]
);
} else
{
Query(
$db,
'UPDATE usersessions
SET data = ?
WHERE uid = ?',
[json_encode($data), $sessionid]
);
}
echo 'Count is ' . $data['count'];
Orain 98 kode-lerro erabili ditugu Laravel-en lau kode-lerro (eta konfigurazio-lan mordoa) egin zutena egiteko. (Noski, erroreen kudeaketa eta erabiltzaileei aurre egiteko mezu egokiak eginez gero, lerro kopuruaren bikoitza izango litzateke.) Agian segundoko 30 eskaera egin ditzakegu?
PHP/Pure PHP
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1
Running 10s test @ http://127.0.0.1
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 140.79ms 27.88ms 332.31ms 90.75%
Req/Sec 178.63 58.34 252.00 61.01%
7074 requests in 10.04s, 3.62MB read
Requests/sec: 704.46
Transfer/sec: 369.43KB
Aupa! Badirudi azken finean ez dagoela ezer okerrik gure PHP instalazioarekin. PHP bertsio hutsa segundoko 700 eskaera egiten ari da.
PHPrekin ezer okerrik ez badago, agian gaizki konfiguratu dugu Laravel?
Weba arakatu ondoren konfigurazio-arazoak eta errendimendu-aholkuak bilatzeko, teknikarik ezagunenetako bi konfigurazio-datuak cachean gordetzea eta bideratzea izan ziren, eskaera bakoitzerako prozesatzea ekiditeko. Hori dela eta, haien aholkuak hartuko ditugu eta aholku hauek probatuko ditugu.
โฐโโค php artisan config:cache
INFO Configuration cached successfully.
โฐโโค php artisan route:cache
INFO Routes cached successfully.
Dena ondo ikusten da komando lerroan. Berregin dezagun erreferentzia.
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1
Running 10s test @ http://127.0.0.1
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.13s 543.50ms 1.98s 61.90%
Req/Sec 25.45 13.39 50.00 55.77%
289 requests in 10.04s, 242.15KB read
Socket errors: connect 0, read 0, write 0, timeout 247
Requests/sec: 28.80
Transfer/sec: 24.13KB
Beno, orain errendimendua handitu dugu segundoko 21.04tik 28.80 eskaerara, ia % 37ko igoera izugarria! Hau nahiko ikusgarria izango litzateke edozein software paketerentzat... izan ezik, oraindik ere PHP hutsezko bertsioaren eskaera kopuruaren 1/24 baino ez dugula egiten'
Proba honekin zerbait gaizki egon behar dela pentsatzen baduzu, Lucinda PHP frameworkaren egilearekin hitz egin beharko zenuke. Bere proben emaitzetan, du Lucinda Laravel irabazten 36x HTML eskaeretarako eta 90x JSON eskaeretarako.
Apache eta Nginx-ekin nire makinan probatu ondoren, ez dut haren zalantzan jartzeko arrazoirik. Laravel benetan justua da hori motel! PHP berez ez da hain txarra, baina Laravelek eskaera bakoitzari gehitzen dion prozesamendu gehigarri guztia gehitzen duzunean, oso zaila iruditzen zait Laravel 2023an aukera gisa gomendatzea.
PHP/Wordpress kontuetarako sareko webgune guztien %40 inguru , marko nagusiena bihurtuz, alde handiz. Pertsonalki, baina, uste dut ospea ez dela zertan kalitatean itzultzen, eta ez dudan bat-batean janari gourmet aparteko gogoa kontrolaezina sentitzen dudana baino. munduko jatetxerik ezagunena ... McDonald's. Dagoeneko PHP kode hutsa probatu dugunez, ez dugu Wordpress bera probatuko, Wordpress inplikatzen duen edozer PHP hutsarekin ikusi genituen segundoko 700 eskaerak baino txikiagoa izango litzateke dudarik gabe.
Django aspalditik dagoen beste esparru ezagun bat da. Iraganean erabili bazenuen, ziurrenik ederki gogoan izango duzu bere datu-baseen administrazio-interfaze ikusgarria eta dena nahi zenuen moduan konfiguratzea zein gogaikarria zen. Ikus dezagun Django-k 2023an nola funtzionatzen duen, batez ere 4.0 bertsiotik aurrera gehitu duen ASGI interfaze berriarekin.
Django konfiguratzea Laravel konfiguratzearen antzekoa da, biak baitziren MVC arkitektura dotoreak eta zuzenak ziren garaikoak. Konfigurazio aspergarria saltatuko dugu eta zuzenean ikuspegia konfiguratzera joango gara.
from django.shortcuts import render
from django.http import HttpResponse
# =====================================================================
def index(request):
count = request.session.get('count', 0)
count += 1
request.session['count'] = count
return HttpResponse(f"Count is {count}")
Lau kode lerro Laravel bertsioarekin berdinak dira. Ikus dezagun nola funtzionatzen duen.
โฐโโค python --version
Python 3.10.9
Python/Django
โฐโโค gunicorn --access-logfile - -k uvicorn.workers.UvicornWorker -w 4 djangotest.asgi
[2023-03-21 15:20:38 +0800] [2886633] [INFO] Starting gunicorn 20.1.0
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1:8000/sessiontest/
Running 10s test @ http://127.0.0.1:8000/sessiontest/
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 277.71ms 142.84ms 835.12ms 69.93%
Req/Sec 91.21 57.57 230.00 61.04%
3577 requests in 10.06s, 1.46MB read
Requests/sec: 355.44
Transfer/sec: 148.56KB
Ez dago batere gaizki segundoko 355 eskaerarekin. PHP bertsio hutsaren errendimenduaren erdia baino ez da, baina Laravel bertsioarena ere 12 aldiz handiagoa da. Django vs. Laravel badirudi ez dela inolako lehiarik.
Dena-sukaldea-harraska-esparru handiagoez gain, oinarrizko konfigurazio batzuk egiten dituzten marko txikiagoak ere badaude gainerakoa kudeatzen uzten dizuten bitartean. Erabiltzeko onenetako bat Flask eta bere ASGI Quart da. Nirea PaferaPy esparrua Flask-en gainean eraikita dago, beraz, ongi dakit zein erraza den gauzak egitea errendimendua mantenduz.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Session benchmark test
import json
import psycopg
import uuid
from flask import Flask, session, redirect, url_for, request, current_app, g, abort, send_from_directory
from flask.sessions import SecureCookieSessionInterface
app = Flask('pafera')
app.secret_key = b'secretkey'
dbconn = 0
# =====================================================================
@app.route('/', defaults={'path': ''}, methods = ['GET', 'POST'])
@app.route('/<path:path>', methods = ['GET', 'POST'])
def index(path):
"""Handles all requests for the server.
We route all requests through here to handle the database and session
logic in one place.
"""
global dbconn
if not dbconn:
dbconn = psycopg.connect('dbname=sessiontest user=sessiontest password=sessiontest')
cursor = dbconn.execute('''
CREATE TABLE IF NOT EXISTS usersessions(
uid TEXT PRIMARY KEY,
data TEXT
)
''')
cursor.close()
dbconn.commit()
sessionid = session.get('sessionid', 0)
if not sessionid:
sessionid = uuid.uuid4().hex
session['sessionid'] = sessionid
cursor = dbconn.execute("SELECT data FROM usersessions WHERE uid = %s", [sessionid])
row = cursor.fetchone()
count = json.loads(row[0])['count'] if row else 0
count += 1
newdata = json.dumps({'count': count})
if count == 1:
cursor.execute("""
INSERT INTO usersessions(uid, data)
VALUES(%s, %s)
""",
[sessionid, newdata]
)
else:
cursor.execute("""
UPDATE usersessions
SET data = %s
WHERE uid = %s
""",
[newdata, sessionid]
)
cursor.close()
dbconn.commit()
return f'Count is {count}'
Ikus dezakezunez, Flask script-a PHP script hutsa baino laburragoa da. Erabili ditudan hizkuntza guztien artean, Python da, ziurrenik, tekla sakatzeei dagokienez, hizkuntza adierazgarriena. Giltza eta parentesirik ezak, zerrenda eta diktuaren ulermenak eta puntu eta koma baino koskatan oinarritutako blokeatzeak Python sinple samarra da, baina bere gaitasunetan indartsua.
Zoritxarrez, Python helburu orokorreko hizkuntza motelena ere bada, bertan zenbat software idatzi den arren. Eskuragarri dauden Python liburutegien kopurua antzeko hizkuntzak baino lau aldiz handiagoa da eta domeinu ugari hartzen ditu, baina inork ez luke esango Python azkarra edo eraginkorra denik NumPy bezalako nitxoetatik kanpo.
Ikus dezagun gure Flask bertsioa gure aurreko esparruekin alderatzen den.
Python/Flask
โฐโโค gunicorn --access-logfile - -w 4 flasksite:app
[2023-03-21 15:32:49 +0800] [2856296] [INFO] Starting gunicorn 20.1.0
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1:8000
Running 10s test @ http://127.0.0.1:8000
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 91.84ms 11.97ms 149.63ms 86.18%
Req/Sec 272.04 39.05 380.00 74.50%
10842 requests in 10.04s, 3.27MB read
Requests/sec: 1080.28
Transfer/sec: 333.37KB
Gure Flask script-a benetan gure PHP bertsio hutsa baino azkarragoa da!
Honekin harritzen bazaizu, konturatu beharko zenuke gure Flask aplikazioak hasierako eta konfigurazio guztia egiten duela gunicorn zerbitzaria abiarazten dugunean, eta PHP-k scripta berriro exekutatzen du eskaera berri bat sartzen den bakoitzean.' ;Flask autoa martxan jarri eta errepide ondoan zain dagoen taxi gidari gazte eta irritsu izatearen baliokidea da, PHP bere etxean dei baten zain geratzen den eta orduan bakarrik gidatzen duen gidari zaharra da. zu hartzera. Eskola zaharreko mutila izanik eta PHP HTML eta SHTML fitxategi arruntetarako aldaketa zoragarria izan zen garaietatik etorrita, triste samarra da zenbat denbora igaro den konturatzea, baina diseinu-desberdintasunek benetan zaila egiten diote PHP-ri lehiatu Python, Java eta Node.js zerbitzarien aurka, memorian geratzen diren eta eskaerak malabarista baten erraztasun arinarekin kudeatzen dituztenak.
Flask izan daiteke orain arteko gure esparrurik azkarrena, baina benetan software zaharra da. Python komunitatea ASGI zerbitzari asinkrono berrietara aldatu zen duela pare bat urte, eta, jakina, ni neu aldatu naiz haiekin batera.
Pafera Markoaren bertsio berriena, PaferaPyAsync , Starletten oinarritzen da. Quart izeneko Flask-en ASGI bertsioa badago ere, Quart eta Starlette-ren arteko errendimendu-desberdintasunak nahikoak izan ziren nire kodea Starlette-n oinarritzeko.
Programazio asinkronoak jende askori beldurra eman diezaioke, baina ez da kontzeptu zaila duela hamarkada bat baino gehiago Node.js-eko mutilei esker.
Hari anitzeko, prozesamendu anitzeko, konputazio banatuarekin, promesa katearekin eta programatzaile beterano asko lehenago zahartu eta lehortzen zituzten garai dibertigarri haiekin batera borrokatzen genuen. Orain, idazten dugu async
gure funtzioen aurrean eta await
exekutatzeko denbora behar izan dezakeen edozein koderen aurrean. Kode arrunta baino zehatzagoa da, baina askoz gogaikarriagoa da erabiltzeko sinkronizazio primitiboekin, mezuen pasabideekin eta promesak ebatzi behar izatea baino.
Gure Starlette fitxategiak itxura hau du:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Session benchmark test
import json
import uuid
import psycopg
from starlette.applications import Starlette
from starlette.responses import Response, PlainTextResponse, JSONResponse, RedirectResponse, HTMLResponse
from starlette.routing import Route, Mount, WebSocketRoute
from starlette_session import SessionMiddleware
dbconn = 0
# =====================================================================
async def index(R):
global dbconn
if not dbconn:
dbconn = await psycopg.AsyncConnection.connect('dbname=sessiontest user=sessiontest password=sessiontest')
cursor = await dbconn.execute('''
CREATE TABLE IF NOT EXISTS usersessions(
uid TEXT PRIMARY KEY,
data TEXT
)
''')
await cursor.close()
await dbconn.commit()
sessionid = R.session.get('sessionid', 0)
if not sessionid:
sessionid = uuid.uuid4().hex
R.session['sessionid'] = sessionid
cursor = await dbconn.execute("SELECT data FROM usersessions WHERE uid = %s", [sessionid])
row = await cursor.fetchone()
count = json.loads(row[0])['count'] if row else 0
count += 1
newdata = json.dumps({'count': count})
if count == 1:
await cursor.execute("""
INSERT INTO usersessions(uid, data)
VALUES(%s, %s)
""",
[sessionid, newdata]
)
else:
await cursor.execute("""
UPDATE usersessions
SET data = %s
WHERE uid = %s
""",
[newdata, sessionid]
)
await cursor.close()
await dbconn.commit()
return PlainTextResponse(f'Count is {count}')
# *********************************************************************
app = Starlette(
debug = True,
routes = [
Route('/{path:path}', index, methods = ['GET', 'POST']),
],
)
app.add_middleware(
SessionMiddleware,
secret_key = 'testsecretkey',
cookie_name = "pafera",
)
Ikus dezakezunez, gure Flask scriptetik nahiko kopiatu eta itsatsi da bideratze-aldaketa pare batekin eta async/await
gako-hitzak.
Zenbat hobekuntza ekar diezaguke benetan kopiatu eta itsatsitako kodea?
Python/Starlette
โฐโโค gunicorn --access-logfile - -k uvicorn.workers.UvicornWorker -w 4 starlettesite:app 130 โต
[2023-03-21 15:42:34 +0800] [2856220] [INFO] Starting gunicorn 20.1.0
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1:8000
Running 10s test @ http://127.0.0.1:8000
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.85ms 10.45ms 67.29ms 55.18%
Req/Sec 1.15k 170.11 1.52k 66.00%
45809 requests in 10.04s, 13.85MB read
Requests/sec: 4562.82
Transfer/sec: 1.38MB
Txapeldun berria dugu, jaun-andreok! Gure aurreko altua gure PHP bertsio hutsa izan zen segundoko 704 eskaerarekin, eta gero gure Flask bertsioa gainditu zuen segundoko 1080 eskaerarekin. Gure Starlette gidoiak aurreko lehiakide guztiak zapaltzen ditu segundoko 4562 eskaerarekin, hau da, PHP hutsaren 6 aldiz hobetzea eta Flask baino 4 aldiz hobetzea.
Oraindik ez baduzu zure WSGI Python kodea ASGIra aldatu, orain hasteko une egokia izan daiteke.
Orain arte, PHP eta Python esparruak soilik estali ditugu. Hala ere, munduko zati handi batek Java, DotNet, Node.js, Ruby on Rails eta horrelako beste teknologia batzuk erabiltzen ditu bere webguneetarako. Hau ez da inolaz ere munduko ekosistema eta bioma guztien ikuspegi orokorra, beraz, kimika organikoaren programazio baliokidea egitea saihesteko, kodea idazteko errazenak diren esparruak bakarrik aukeratuko ditugu. Java ez da zalantzarik gabe.
K&R C edo Knuth's kopiaren azpian ezkutatuta egon ez bazara. Ordenagailuen Programazioaren Artea azken hamabost urteotan, seguruenik, Node.js-en berri izan duzu. JavaScript-en hasieratik egon garenok izugarri beldurtuta, harrituta gaude edo biak JavaScript modernoaren egoerarekin, baina ezin da ukatu JavaScript zerbitzarietan ere kontuan hartu beharreko indarra bihurtu dela. nabigatzaile gisa. Azken finean, jatorrizko 64 biteko zenbaki osoak ere baditugu hizkuntzan! Hori 64 biteko flotagailuetan gordeta dagoen guztia baino askoz hobea da!
ExpressJS da seguruenik erabiltzeko errazena Node.js zerbitzaria, beraz, Node.js/ExpressJS aplikazio azkar eta zikin bat egingo dugu gure kontagailua zerbitzatzeko.
/**********************************************************************
* Simple session test using ExpressJS.
**********************************************************************/
var L = console.log;
var uuid = require('uuid4');
var express = require('express');
var session = require('express-session');
var MemoryStore = require('memorystore')(session);
var { Client } = require('pg')
var db = 0;
var app = express();
const PORT = 8000;
//session middleware
app.use(
session({
secret: "secretkey",
saveUninitialized: true,
resave: false,
store: new MemoryStore({
checkPeriod: 1000 * 60 * 60 * 24 // prune expired entries every 24h
})
})
);
app.get('/',
async function(req,res)
{
if (!db)
{
db = new Client({
user: 'sessiontest',
host: '127.0.0.1',
database: 'sessiontest',
password: 'sessiontest'
});
await db.connect();
await db.query(`
CREATE TABLE IF NOT EXISTS usersessions(
uid TEXT PRIMARY KEY,
data TEXT
)`,
[]
);
};
var session = req.session;
if (!session.sessionid)
{
session.sessionid = uuid();
}
var row = 0;
let queryresult = await db.query(`
SELECT data::TEXT
FROM usersessions
WHERE uid = $1`,
[session.sessionid]
);
if (queryresult && queryresult.rows.length)
{
row = queryresult.rows[0].data;
}
var count = 0;
if (row)
{
var data = JSON.parse(row);
data.count += 1;
count = data.count;
await db.query(`
UPDATE usersessions
SET data = $1
WHERE uid = $2
`,
[JSON.stringify(data), session.sessionid]
);
} else
{
await db.query(`
INSERT INTO usersessions(uid, data)
VALUES($1, $2)`,
[session.sessionid, JSON.stringify({count: 1})]
);
count = 1;
}
res.send(`Count is ${count}`);
}
);
app.listen(PORT, () => console.log(`Server Running at port ${PORT}`));
Kode hau Python bertsioak baino idazteko errazagoa zen, nahiz eta jatorrizko JavaScript nahiko zaila den aplikazioak handitzen direnean, eta hau zuzentzeko saiakera guztiak, esate baterako, TypeScript, Python-ek baino arinagoak bihurtzen dira.
Ea nola funtzionatzen duen!
Node.js/ExpressJS
โฐโโค node --version v19.6.0
โฐโโค NODE_ENV=production node nodejsapp.js 130 โต
Server Running at port 8000
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1:8000
Running 10s test @ http://127.0.0.1:8000
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 90.41ms 7.20ms 188.29ms 85.16%
Req/Sec 277.15 37.21 393.00 81.66%
11018 requests in 10.02s, 3.82MB read
Requests/sec: 1100.12
Transfer/sec: 390.68KB
Baliteke Node.js' abiadura, eta istorio horiek egiazkoak dira gehienbat Google-k V8 JavaScript motorearekin egin duen lan ikusgarriari esker. Kasu honetan, baina, gure aplikazio azkarrak Flask script-a gainditzen duen arren, bere hari bakarreko izaerak garaitzen ditu "Ni!" esaten duen Starlette Knight-ek erabiltzen dituen lau prozesu asinkronikoek.
Lor dezagun laguntza gehiago!
โฐโโค pm2 start nodejsapp.js -i 4
[PM2] Spawning PM2 daemon with pm2_home=/home/jim/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/jim/projects/paferarust/nodejsapp.js in cluster_mode (4 instances)
[PM2] Done.
โโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโฌโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโ
โ id โ name โ namespace โ version โ mode โ pid โ uptime โ โบ โ status โ cpu โ mem โ user โ watching โ
โโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโผโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโค
โ 0 โ nodejsapp โ default โ N/A โ cluster โ 37141 โ 0s โ 0 โ online โ 0% โ 64.6mb โ jim โ disabled โ
โ 1 โ nodejsapp โ default โ N/A โ cluster โ 37148 โ 0s โ 0 โ online โ 0% โ 64.5mb โ jim โ disabled โ
โ 2 โ nodejsapp โ default โ N/A โ cluster โ 37159 โ 0s โ 0 โ online โ 0% โ 56.0mb โ jim โ disabled โ
โ 3 โ nodejsapp โ default โ N/A โ cluster โ 37171 โ 0s โ 0 โ online โ 0% โ 45.3mb โ jim โ disabled โ
โโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโดโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโ
Ados! Orain lauko lau arteko borroka da! Egin dezagun erreferentzia!
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1:8000
Running 10s test @ http://127.0.0.1:8000
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 45.09ms 19.89ms 176.14ms 60.22%
Req/Sec 558.93 97.50 770.00 66.17%
22234 requests in 10.02s, 7.71MB read
Requests/sec: 2218.69
Transfer/sec: 787.89KB
Oraindik ez dago Starlette-ren mailan, baina ez da txarra bost minutuko JavaScript hack egiteko. Nire proben arabera, script hau apur bat atzera egiten ari da datu-baseen interfaze mailan, node-postgres ez baita inondik inora psycopg Pythonentzat bezain eraginkorra. Sqlite-ra aldatzeak datu-basearen kontrolatzaileak 3000 eskaera baino gehiago ematen ditu segundoko ExpressJS kode berarentzat.
Kontuan izan behar den gauza nagusia da Python-en exekuzio-abiadura motela izan arren, ASGI markoak benetan lehiakorrak izan daitezkeela Node.js irtenbideekin lan-karga jakin batzuetarako.
Beraz, orain, mendi tontorrera hurbiltzen ari gara, eta mendiz, saguek zein gizonek erregistratutako puntuazio altuenak esan nahi dut.
Sarean eskuragarri dauden esparru-erreferentzia gehienei begiratzen badiozu, nabarituko duzu goian nagusi izan ohi diren bi hizkuntza daudela: C++ eta Rust. 90eko hamarkadatik C++-rekin lan egin dut, eta nire Win32 C++ esparru propioa ere banuen MFC/ATL gauza izan baino lehen, beraz, esperientzia handia dut hizkuntzarekin. Ez da oso dibertigarria zerbaitekin lan egitea dagoeneko ezagutzen duzunean, beraz, Rust bertsio bat egingo dugu. ;)
Rust nahiko berria da programazio-lengoaiari dagokionez, baina jakin-min objektu bihurtu zitzaidan Linus Torvaldsek Rust Linux kernel programazio-lengoaia gisa onartuko zuela iragarri zuenean. Programatzaile zaharragook, hau da, AEBetako Konstituzioaren aldaketa berri bat izango zela esatea.
Orain, eskarmentu handiko programatzailea zarenean, gazteenek bezain azkar karroan ez salto egin ohi duzu, edo, bestela, baliteke hizkuntzaren edo liburutegien aldaketa azkarrek erretzea. (AngularJS-en lehen bertsioa erabili duen edonork jakingo du zertaz ari naizen.) Rust garapen esperimentalaren fase horretan dago oraindik, eta dibertigarria iruditzen zait sareko kode-adibide asko ez izatea. konpilatu gehiago paketeen egungo bertsioekin.
Hala ere, Rust aplikazioek erakusten duten errendimendua ezin da ukatu. Inoiz saiatu ez bazara ripgrep edo fd-aurkitu iturburu-kodeen zuhaitz handietan, behin betiko buelta bat eman beharko diezu. Linux banaketa gehienetarako ere eskuragarri daude paketeen kudeatzailetik. Rust-ekin hitzezkotasuna trukatzen ari zara... a asko verbositatearen batentzat asko errendimenduaren.
Rust-en kode osoa handi samarra da, beraz, hemen dagozkion kudeatzaileei begiratu bat emango diegu:
// =====================================================================
pub async fn RunQuery(
db: &web::Data<Pool>,
query: &str,
args: &[&(dyn ToSql + Sync)]
) -> Result<Vec<tokio_postgres::row::Row>, tokio_postgres::Error>
{
let client = db.get().await.unwrap();
let statement = client.prepare_cached(query).await.unwrap();
client.query(&statement, args).await
}
// =====================================================================
pub async fn index(
req: HttpRequest,
session: Session,
db: web::Data<Pool>,
) -> Result<HttpResponse, Error>
{
let mut count = 1;
if let Some(sessionid) = session.get::<String>("sessionid")?
{
let rows = RunQuery(
&db,
"SELECT data
FROM usersessions
WHERE uid = $1",
&[&sessionid]
).await.unwrap();
if rows.is_empty()
{
let jsondata = serde_json::json!({
"count": 1,
}).to_string();
RunQuery(
&db,
"INSERT INTO usersessions(uid, data)
VALUES($1, $2)",
&[&sessionid, &jsondata]
).await
.expect("Insert failed!");
} else
{
let jsonstring:&str = rows[0].get(0);
let countdata: CountData = serde_json::from_str(jsonstring)?;
count = countdata.count;
count += 1;
let jsondata = serde_json::json!({
"count": count,
}).to_string();
RunQuery(
&db,
"UPDATE usersessions
SET data = $1
WHERE uid = $2
",
&[&jsondata, &sessionid]
).await
.expect("Update failed!");
}
} else
{
let sessionid = Uuid::new_v4().to_string();
let jsondata = serde_json::json!({
"count": 1,
}).to_string();
RunQuery(
&db,
"INSERT INTO usersessions(uid, data)
VALUES($1, $2)",
&[&sessionid, &jsondata]
).await
.expect("Insert failed!");
session.insert("sessionid", sessionid)?;
}
Ok(HttpResponse::Ok().body(format!(
"Count is {:?}",
count
)))
}
Hau Python/Node.js bertsioak baino askoz konplexuagoa da...
Rust/Actix
โฐโโค cargo run --release
[2023-03-21T23:37:25Z INFO actix_server::builder] starting 4 workers
Server running at http://127.0.0.1:8888/
โฐโโค wrk -d 10s -t 4 -c 100 http://127.0.0.1:8888
Running 10s test @ http://127.0.0.1:8888
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 9.93ms 3.90ms 77.18ms 94.87%
Req/Sec 2.59k 226.41 2.83k 89.25%
102951 requests in 10.03s, 24.59MB read
Requests/sec: 10267.39
Transfer/sec: 2.45MB
Eta askoz errendimendu handiagoa!
Gure Rust zerbitzariak Actix/deadpool_postgres erabiliz modu errazean gainditzen du gure aurreko txapeldun Starlette % 125, ExpressJS % 362 eta PHP hutsa % 1366. (Emanaldiko delta Laravel bertsioarekin utziko dut irakurlearentzat ariketa gisa.)
Rust hizkuntza bera ikastea beste hizkuntzak baino zailagoa izan dela ikusi dut, 6502 Assembly-tik kanpo ikusi dudan ezer baino askoz ere jokabide gehiago dituelako, baina zure Rust zerbitzariak 14 aldiz gehiago har ditzake. erabiltzaileak zure PHP zerbitzari gisa, orduan agian zerbait irabazi behar da teknologiak aldatzearekin. Horregatik, Pafera Markoaren hurrengo bertsioa Rust-en oinarrituko da. Ikasketa-kurba scripting lengoaiak baino askoz handiagoa da, baina errendimenduak mereziko du. Rust ikasteko denborarik eman ezin baduzu, zure teknologia-pila Starlette edo Node.js-en oinarritzea ere ez da erabaki txarra.
Azken hogei urteotan, ostalaritza-gune estatiko merkeetatik LAMP pilarekin ostalaritza partekatuetara pasa gara VPSak AWS, Azure eta hodeiko beste zerbitzu batzuetara alokatzera. Gaur egun, enpresa asko pozik daude diseinu-erabakiak hartzerakoan, eskuragarri edo merkeena den edonoren arabera, hodeiko zerbitzu erosoen agerpenetik zerbitzari eta aplikazio moteletara hardware gehiago botatzea erraztu baitute. Horrek epe laburreko irabazi handiak eman dizkie epe luzeko zor teknikoaren kostuan.
Duela 70 urte, Sobietar Batasunaren eta Estatu Batuen arteko espazio-lasterketa handia izan zen. Sobietarrek hasierako mugarri gehienak irabazi zituzten. Sputniken lehen satelitea izan zuten, Laikan espazioko lehen txakurra, Luna 2ko lehen ilargi-ontzia, espazioko lehen gizon-emakumea Yuri Gagarin eta Valentina Tereshkova eta abar...
Baina poliki-poliki zor teknikoa pilatzen ari ziren.
Sobietarrak lorpen horietako bakoitzean lehenak izan baziren ere, haien ingeniaritza-prozesuek eta helburuek epe laburreko erronketan zentratu zuten epe luzeko bideragarritasunean baino. Jauzi egiten zuten bakoitzean irabazi zuten, baina gero eta nekatuago eta motelagoak ziren aurkariek helmugan urrats sendoak ematen jarraitzen zuten bitartean.
Behin Neil Armstrong-ek zuzeneko telebistan ilargian bere urrats historikoak eman zituenean, estatubatuarrek hartu zuten aurrea, eta gero han geratu ziren sobietar programa kolokan zegoen bitartean. Hau ez da gaur egun hurrengo gauza handian, hurrengo ordain handian edo hurrengo teknologia handian zentratu diren enpresen aldean, epe luzerako ohitura eta estrategia egokiak garatzen ez dituzten bitartean.
Merkatuan lehena izateak ez du esan nahi merkatu horretan nagusi izango zarenik. Bestela, gauzak ondo egiteko denbora hartzeak ez du arrakasta bermatzen, baina, zalantzarik gabe, epe luzerako lorpenak lortzeko aukerak areagotzen ditu. Zure enpresaren teknologia-burua bazara, aukeratu norabide eta tresna egokiak zure lan-kargarako. Ez utzi ospeak errendimendua eta eraginkortasuna ordezkatzen.
Rust, ExpressJS, Flask, Starlette eta Pure PHP scriptak dituen 7z fitxategi bat deskargatu nahi duzu?
Egileari buruz |
|
![]() |
Jim 90eko hamarkadan IBM PS/2 bat lortu zuenetik programatzen ari da. Gaur egun, oraindik nahiago du HTML eta SQL eskuz idaztea, eta eraginkortasuna eta zuzentasuna du arreta bere lanean. |