اپنے حالیہ ملازمت کے انٹرویوز میں سے ایک کے بعد، مجھے یہ جان کر حیرت ہوئی کہ میں نے جس کمپنی کے لیے درخواست دی تھی وہ ابھی تک لاراول استعمال کر رہی تھی، ایک پی ایچ پی فریم ورک جسے میں نے تقریباً ایک دہائی قبل آزمایا تھا۔ یہ اس وقت کے لیے مہذب تھا، لیکن اگر ٹیکنالوجی اور فیشن میں ایک ہی مستقل ہے، تو یہ طرزوں اور تصورات کی مسلسل تبدیلی اور دوبارہ سرفہرست ہے۔ اگر آپ جاوا اسکرپٹ پروگرامر ہیں، تو آپ شاید اس پرانے لطیفے سے واقف ہوں گے۔
پروگرامر 1: "مجھے یہ نیا JavaScript فریم ورک پسند نہیں ہے!"
پروگرامر 2: "پریشان ہونے کی ضرورت نہیں ہے۔ بس چھ مہینے انتظار کریں اور اس کی جگہ کوئی اور آئے گا!"
تجسس کی وجہ سے، میں نے یہ دیکھنے کا فیصلہ کیا کہ جب ہم پرانے اور نئے کو جانچتے ہیں تو کیا ہوتا ہے۔ یقینا، ویب بینچ مارکس اور دعووں سے بھرا ہوا ہے، جن میں سے سب سے زیادہ مقبول شاید ہے TechEmpower ویب فریم ورک بینچ مارکس یہاں . اگرچہ ہم آج ان کی طرح پیچیدہ کچھ نہیں کرنے جا رہے ہیں۔ ہم چیزوں کو اچھی اور سادہ رکھیں گے تاکہ یہ مضمون تبدیل نہ ہو جنگ اور امن , اور یہ کہ جب آپ پڑھ چکے ہوں گے تب تک آپ کے جاگنے کا تھوڑا سا موقع ہوگا۔ معمول کے انتباہات لاگو ہوتے ہیں: یہ آپ کی مشین پر ایک جیسا کام نہیں کر سکتا، سافٹ ویئر کے مختلف ورژن کارکردگی کو متاثر کر سکتے ہیں، اور شروڈنگر کی بلی دراصل ایک زومبی بلی بن گئی تھی جو عین وقت پر آدھی زندہ اور آدھی مردہ تھی۔
اس ٹیسٹ کے لیے، میں اپنا لیپ ٹاپ استعمال کروں گا جس میں ایک پنی i5 چل رہا ہے جو یہاں دکھایا گیا ہے۔
╰─➤ 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
ہمارے کوڈ میں ہر درخواست کے لیے تین آسان کام ہوں گے:
آپ پوچھ سکتے ہیں کہ یہ کس قسم کا احمقانہ امتحان ہے؟ ٹھیک ہے، اگر آپ اس صفحہ کے لیے نیٹ ورک کی درخواستوں پر نظر ڈالیں گے، تو آپ سیشنvars.js نامی ایک دیکھیں گے جو بالکل وہی کام کرتا ہے۔
آپ دیکھتے ہیں، جدید ویب صفحات پیچیدہ مخلوق ہیں، اور سب سے عام کاموں میں سے ایک پیچیدہ صفحات کو محفوظ کرنا ہے تاکہ ڈیٹا بیس سرور پر اضافی بوجھ سے بچا جا سکے۔
اگر ہم ایک پیچیدہ صفحہ کو ہر بار رینڈر کرتے ہیں جب کوئی صارف اس کی درخواست کرتا ہے، تو ہم فی سیکنڈ صرف 600 صارفین کی خدمت کر سکتے ہیں۔
╰─➤ 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
لیکن اگر ہم اس صفحہ کو ایک جامد HTML فائل کے طور پر کیش کرتے ہیں اور Nginx کو تیزی سے اسے ونڈو سے باہر صارف کے سامنے ٹاس کرنے دیتے ہیں، تو ہم فی سیکنڈ 32,000 صارفین کی خدمت کر سکتے ہیں، جس سے کارکردگی میں 50x اضافہ ہو گا۔
╰─➤ 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
static index.en.html وہ حصہ ہے جو ہر کسی کو جاتا ہے، اور صرف وہی حصے جو صارف کے لحاظ سے مختلف ہوتے ہیں sessionvars.js میں بھیجے جاتے ہیں۔ اس سے نہ صرف ڈیٹا بیس کا بوجھ کم ہوتا ہے اور ہمارے صارفین کے لیے ایک بہتر تجربہ پیدا ہوتا ہے، بلکہ ان کوانٹم امکانات کو بھی کم کر دیتا ہے کہ کلنگنز کے حملے کے وقت ہمارا سرور خود بخود ایک وارپ کور بریک میں بخارات بن جائے گا۔
ہر فریم ورک کے لیے واپس کیے گئے کوڈ کی ایک سادہ ضرورت ہوگی: صارف کو دکھائیں کہ انہوں نے کتنی بار "Count is x" کہہ کر صفحہ کو ریفریش کیا ہے۔ چیزوں کو آسان رکھنے کے لیے، ہم ابھی کے لیے Redis queues، Kubernetes اجزاء، یا AWS Lambdas سے دور رہیں گے۔
ہر صارف کے سیشن کا ڈیٹا PostgreSQL ڈیٹا بیس میں محفوظ کیا جائے گا۔
اور یہ ڈیٹا بیس ٹیبل ہر ٹیسٹ سے پہلے تراشا جائے گا۔
سادہ لیکن موثر ہے Pafera کا نعرہ... بہرحال تاریک ترین ٹائم لائن سے باہر...
ٹھیک ہے، تو اب ہم آخر کار اپنے ہاتھوں کو گندا کرنا شروع کر سکتے ہیں۔ ہم Laravel کے سیٹ اپ کو چھوڑ دیں گے کیونکہ یہ صرف کمپوزر اور کاریگر کا ایک گروپ ہے احکامات
سب سے پہلے، ہم اپنے ڈیٹا بیس کی ترتیبات .env فائل میں ترتیب دیں گے۔
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=sessiontest
DB_USERNAME=sessiontest
DB_PASSWORD=sessiontest
پھر ہم ایک واحد فال بیک روٹ سیٹ کریں گے جو ہمارے کنٹرولر کو ہر درخواست بھیجتا ہے۔
Route::fallback(SessionController::class);
اور گنتی ظاہر کرنے کے لیے کنٹرولر سیٹ کریں۔ Laravel، بطور ڈیفالٹ، ڈیٹا بیس میں سیشنز کو اسٹور کرتا ہے۔ یہ بھی فراہم کرتا ہے session()
ہمارے سیشن ڈیٹا کے ساتھ انٹرفیس کرنے کے لیے فنکشن، اس لیے ہمارے صفحہ کو رینڈر کرنے کے لیے کوڈ کی چند لائنیں لگیں۔
class SessionController extends Controller
{
public function __invoke(Request $request)
{
$count = session('count', 0);
$count += 1;
session(['count' => $count]);
return 'Count is ' . $count;
}
}
php-fpm اور Nginx ترتیب دینے کے بعد، ہمارا صفحہ کافی اچھا لگتا ہے...
╰─➤ 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
کم از کم اس وقت تک جب تک کہ ہم اصل میں ٹیسٹ کے نتائج نہیں دیکھتے...
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
نہیں، یہ کوئی ٹائپنگ نہیں ہے۔ ہماری ٹیسٹ مشین 600 درخواستیں فی سیکنڈ سے ایک پیچیدہ صفحہ پیش کرتی ہے... سے 21 درخواستیں فی سیکنڈ رینڈرنگ "گنتی 1 ہے"
تو کیا غلط ہوا؟ کیا ہماری پی ایچ پی کی تنصیب میں کچھ غلط ہے؟ کیا php-fpm کے ساتھ انٹرفیس کرتے وقت Nginx کسی طرح سست ہو رہا ہے؟
آئیے اس صفحہ کو خالص پی ایچ پی کوڈ میں دوبارہ کریں۔
<?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'];
اب ہم نے کوڈ کی 98 لائنیں استعمال کی ہیں جو Laravel میں کوڈ کی چار لائنوں (اور کنفیگریشن کے کام کا ایک پورا گروپ) نے کیا تھا۔ (یقیناً، اگر ہم نے غلطی کو درست طریقے سے سنبھالا اور صارف کو پیغامات کا سامنا کرنا پڑا، تو یہ لائنوں کی تعداد سے تقریباً دوگنا ہوگا۔) شاید ہم اسے 30 درخواستیں فی سیکنڈ تک پہنچا سکتے ہیں؟
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
واہ! ایسا لگتا ہے کہ ہماری پی ایچ پی کی تنصیب میں کوئی بھی حرج نہیں ہے۔ خالص پی ایچ پی ورژن 700 درخواستیں فی سیکنڈ کر رہا ہے۔
اگر پی ایچ پی میں کچھ غلط نہیں ہے، تو شاید ہم نے لاراول کو غلط کنفیگر کیا ہے؟
کنفیگریشن ایشوز اور پرفارمنس ٹپس کے لیے ویب کو اسکور کرنے کے بعد، دو سب سے مشہور تکنیکیں ہر درخواست کے لیے ان پر کارروائی کرنے سے بچنے کے لیے کنفیگریشن اور روٹ ڈیٹا کو کیش کرنا تھیں۔ لہذا، ہم ان کے مشورہ لیں گے اور ان تجاویز کو آزمائیں گے.
╰─➤ php artisan config:cache
INFO Configuration cached successfully.
╰─➤ php artisan route:cache
INFO Routes cached successfully.
کمانڈ لائن پر سب کچھ اچھا لگتا ہے۔ آئیے بینچ مارک کو دوبارہ کریں۔
╰─➤ 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
ٹھیک ہے، اب ہم نے کارکردگی کو 21.04 سے بڑھا کر 28.80 درخواست فی سیکنڈ کر دیا ہے، جو تقریباً 37% کی ڈرامائی ترقی ہے! یہ کسی بھی سافٹ ویئر پیکج کے لیے کافی متاثر کن ہوگا... سوائے اس حقیقت کے کہ ہم ابھی بھی خالص پی ایچ پی ورژن کی درخواستوں کی تعداد کا صرف 1/24 حصہ کر رہے ہیں۔
اگر آپ سوچ رہے ہیں کہ اس ٹیسٹ میں کچھ غلط ہونا چاہیے، تو آپ کو لوسینڈا پی ایچ پی فریم ورک کے مصنف سے بات کرنی چاہیے۔ اس کے ٹیسٹ کے نتائج میں، اس نے لوسنڈا لاراول کو مار رہی ہے۔ HTML درخواستوں کے لیے 36x اور JSON درخواستوں کے لیے 90x۔
Apache اور Nginx دونوں کے ساتھ میری اپنی مشین پر جانچ کرنے کے بعد، میرے پاس اس پر شک کرنے کی کوئی وجہ نہیں ہے۔ Laravel واقعی انصاف ہے کہ سست! PHP بذات خود اتنا برا نہیں ہے، لیکن ایک بار جب آپ Laravel کی ہر درخواست میں اضافی پروسیسنگ شامل کر لیتے ہیں، تو مجھے 2023 میں Laravel کو انتخاب کے طور پر تجویز کرنا بہت مشکل لگتا ہے۔
پی ایچ پی/ورڈپریس اکاؤنٹس کے لیے ویب پر موجود تمام ویب سائٹس کا تقریباً 40% ، اسے اب تک کا سب سے غالب فریم ورک بناتا ہے۔ اگرچہ ذاتی طور پر، میں نے محسوس کیا کہ مقبولیت کا معیار میں ترجمہ کرنا ضروری نہیں ہے جتنا کہ میں اپنے آپ کو اس غیر معمولی لذیذ کھانے کے لیے اچانک بے قابو خواہش محسوس کرتا ہوں۔ دنیا کا سب سے مشہور ریستوراں ... میکڈونلڈز چونکہ ہم پہلے ہی خالص PHP کوڈ کا تجربہ کر چکے ہیں، اس لیے ہم خود ورڈپریس کو جانچنے نہیں جا رہے ہیں، کیونکہ ورڈپریس کو شامل کرنے والی کوئی بھی چیز بلاشبہ 700 درخواستوں فی سیکنڈ سے کم ہو گی جو ہم نے خالص PHP کے ساتھ دیکھی ہیں۔
جینگو ایک اور مقبول فریم ورک ہے جو ایک طویل عرصے سے موجود ہے۔ اگر آپ نے اسے ماضی میں استعمال کیا ہے، تو آپ شاید اس کے شاندار ڈیٹا بیس ایڈمنسٹریشن انٹرفیس کو شوق سے یاد کر رہے ہوں گے اور ساتھ ہی ہر چیز کو جس طرح آپ چاہتے تھے ترتیب دینا کتنا پریشان کن تھا۔ آئیے دیکھتے ہیں کہ Django 2023 میں کتنی اچھی طرح سے کام کرتا ہے، خاص طور پر نئے ASGI انٹرفیس کے ساتھ جسے اس نے ورژن 4.0 میں شامل کیا ہے۔
جیانگو کو ترتیب دینا خاص طور پر لاراول کو ترتیب دینے کے مترادف ہے، کیونکہ یہ دونوں اس زمانے سے تھے جہاں MVC فن تعمیر سجیلا اور درست تھے۔ ہم بورنگ کنفیگریشن کو چھوڑ دیں گے اور ویو سیٹ اپ کرنے کے لیے سیدھے جائیں گے۔
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}")
کوڈ کی چار لائنیں Laravel ورژن کی طرح ہی ہیں۔ آئیے دیکھتے ہیں کہ یہ کیسے کام کرتا ہے۔
╰─➤ 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
فی سیکنڈ 355 درخواستوں پر بالکل بھی برا نہیں ہے۔ یہ خالص پی ایچ پی ورژن کی صرف نصف کارکردگی ہے، لیکن یہ لاراول ورژن سے 12 گنا زیادہ ہے۔ Django بمقابلہ Laravel ایسا لگتا ہے کہ کوئی مقابلہ نہیں ہے۔
بڑی ہر چیز کے علاوہ-بشمول باورچی خانے کے سنک فریم ورک کے علاوہ، چھوٹے فریم ورک بھی ہیں جو آپ کو باقی کو سنبھالنے دیتے ہوئے صرف کچھ بنیادی سیٹ اپ کرتے ہیں۔ استعمال کرنے کے لیے بہترین میں سے ایک فلاسک اور اس کا ASGI ہم منصب کوارٹ ہے۔ میرا اپنا PaferaPy فریم ورک فلاسک کے اوپر بنایا گیا ہے، لہذا میں اس بات سے بخوبی واقف ہوں کہ کارکردگی کو برقرار رکھتے ہوئے کام کرنا کتنا آسان ہے۔
#!/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}'
جیسا کہ آپ دیکھ سکتے ہیں، فلاسک اسکرپٹ خالص پی ایچ پی اسکرپٹ سے چھوٹا ہے۔ مجھے معلوم ہوا کہ ان تمام زبانوں میں سے جو میں نے استعمال کی ہیں، Python غالباً ٹائپ کیے گئے کی اسٹروکس کے لحاظ سے سب سے زیادہ اظہار خیال کرنے والی زبان ہے۔ منحنی خطوط وحدانی اور قوسین کی کمی، فہرست اور ڈکٹ کی سمجھ، اور سیمیکولنز کی بجائے انڈینٹیشن پر مبنی بلاکنگ Python کو اپنی صلاحیتوں میں سادہ لیکن طاقتور بناتی ہے۔
بدقسمتی سے، Python وہاں کی سب سے سست عام مقصد کی زبان بھی ہے، باوجود اس کے کہ اس میں کتنا سافٹ ویئر لکھا گیا ہے۔ دستیاب Python لائبریریوں کی تعداد ملتے جلتے زبانوں کے مقابلے میں تقریباً چار گنا زیادہ ہے اور ڈومینز کی ایک بڑی مقدار کا احاطہ کرتی ہے، پھر بھی کوئی یہ نہیں کہے گا کہ Python تیز ہے اور نہ ہی NumPy جیسے طاقوں سے باہر ہے۔
آئیے دیکھتے ہیں کہ ہمارا فلاسک ورژن ہمارے پچھلے فریم ورک سے کیسے موازنہ کرتا ہے۔
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
ہمارا فلاسک اسکرپٹ دراصل ہمارے خالص پی ایچ پی ورژن سے تیز ہے!
اگر آپ اس سے حیران ہیں، تو آپ کو یہ سمجھ لینا چاہیے کہ جب ہم گنی کارن سرور کو سٹارٹ کرتے ہیں تو ہماری فلاسک ایپ اپنی تمام شروعات اور کنفیگریشن کرتی ہے، جبکہ پی ایچ پی ہر بار جب کوئی نئی درخواست آتی ہے تو اسکرپٹ کو دوبارہ عمل میں لاتی ہے۔ فلاسک ایک نوجوان، شوقین ٹیکسی ڈرائیور کے مترادف ہے جس نے پہلے ہی کار اسٹارٹ کر رکھی ہے اور سڑک کے کنارے انتظار کر رہا ہے، جبکہ پی ایچ پی وہ بوڑھا ڈرائیور ہے جو اپنے گھر پر کال آنے کا انتظار کرتا ہے اور تبھی گاڑی چلاتا ہے۔ آپ کو لینے کے لیے۔ اسکول کا ایک پرانا لڑکا ہونے کے ناطے اور ان دنوں سے آرہا ہے جہاں PHP سادہ HTML اور SHTML فائلوں میں ایک حیرت انگیز تبدیلی تھی، یہ سمجھنا قدرے افسوسناک ہے کہ کتنا وقت گزر چکا ہے، لیکن ڈیزائن میں فرق واقعی پی ایچ پی کے لیے مشکل بنا دیتا ہے۔ Python، Java، اور Node.js سرورز سے مقابلہ کریں جو صرف میموری میں رہتے ہیں اور ایک جادوگر کی فرتیلا آسانی کے ساتھ درخواست کو ہینڈل کرتے ہیں۔
فلاسک ہمارا اب تک کا سب سے تیز ترین فریم ورک ہوسکتا ہے، لیکن یہ حقیقت میں کافی پرانا سافٹ ویئر ہے۔ Python کمیونٹی نے کچھ سال پہلے نئے asychronous ASGI سرورز پر سوئچ کیا تھا، اور یقیناً میں نے خود بھی ان کے ساتھ سوئچ کیا ہے۔
پیفیرا فریم ورک کا تازہ ترین ورژن، PaferaPyAsync ، اسٹارلیٹ پر مبنی ہے۔ اگرچہ فلاسک کا ایک ASGI ورژن ہے جسے Quart کہتے ہیں، لیکن Quart اور Starlette کے درمیان کارکردگی کے فرق میرے لیے اس کے بجائے Starlette پر اپنے کوڈ کو ری بیس کرنے کے لیے کافی تھے۔
اسیکرونس پروگرامنگ بہت سے لوگوں کے لیے خوفزدہ ہو سکتی ہے، لیکن یہ حقیقت میں کوئی مشکل تصور نہیں ہے کیونکہ Node.js لڑکوں نے ایک دہائی قبل اس تصور کو مقبول بنایا تھا۔
ہم ملٹی تھریڈنگ، ملٹی پروسیسنگ، ڈسٹری بیوٹڈ کمپیوٹنگ، وعدے کی زنجیر، اور ان تمام تفریحی اوقات کے ساتھ ہم آہنگی کا مقابلہ کرتے تھے جو بہت سے تجربہ کار پروگرامرز کو وقت سے پہلے بوڑھے اور ناکارہ بنا دیتے تھے۔ اب، ہم صرف ٹائپ کرتے ہیں۔ async
ہمارے افعال کے سامنے اور await
کسی بھی کوڈ کے سامنے جس پر عمل درآمد میں کچھ وقت لگ سکتا ہے۔ یہ درحقیقت باقاعدہ کوڈ سے زیادہ لفظی ہے، لیکن مطابقت پذیری کے پرائمیٹوز، میسج پاس کرنے، اور وعدوں کو حل کرنے کے مقابلے میں استعمال کرنا بہت کم پریشان کن ہے۔
ہماری سٹارلیٹ فائل اس طرح دکھتی ہے:
#!/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",
)
جیسا کہ آپ دیکھ سکتے ہیں، یہ ہمارے فلاسک اسکرپٹ سے کافی حد تک کاپی اور پیسٹ کیا گیا ہے جس میں صرف چند روٹنگ تبدیلیاں ہیں اور async/await
مطلوبہ الفاظ
کاپی اور پیسٹ شدہ کوڈ واقعی ہمیں کتنی بہتری دے سکتا ہے؟
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
ہمارے پاس ایک نیا چیمپئن ہے، خواتین و حضرات! ہمارا پچھلا اعلیٰ ہمارا خالص پی ایچ پی ورژن 704 درخواستیں فی سیکنڈ تھا، جسے پھر ہمارے فلاسک ورژن نے 1080 درخواستیں فی سیکنڈ پر پیچھے چھوڑ دیا۔ ہمارا سٹارلیٹ اسکرپٹ تمام پچھلے دعویداروں کو 4562 درخواستوں فی سیکنڈ پر کچل دیتا ہے، یعنی خالص پی ایچ پی پر 6x بہتری اور فلاسک پر 4x بہتری۔
اگر آپ نے ابھی تک اپنے WSGI Python کوڈ کو ASGI میں تبدیل نہیں کیا ہے، تو اب شروع کرنے کا اچھا وقت ہو سکتا ہے۔
اب تک، ہم نے صرف PHP اور Python فریم ورک کا احاطہ کیا ہے۔ تاہم، دنیا کا ایک بڑا حصہ دراصل اپنی ویب سائٹس کے لیے Java، DotNet، Node.js، Ruby on Rails، اور اس طرح کی دیگر ٹیکنالوجیز استعمال کرتا ہے۔ یہ کسی بھی طرح سے دنیا کے تمام ماحولیاتی نظاموں اور بائیومز کا ایک جامع جائزہ نہیں ہے، لہذا نامیاتی کیمسٹری کے مساوی پروگرامنگ کرنے سے بچنے کے لیے، ہم صرف ان فریم ورک کا انتخاب کریں گے جن کے لیے کوڈ ٹائپ کرنا آسان ہے۔ جس میں سے جاوا یقینی طور پر نہیں ہے۔
جب تک کہ آپ K&R C یا Knuth's کی اپنی کاپی کے نیچے چھپا رہے ہوں کمپیوٹر پروگرامنگ کا فن پچھلے پندرہ سالوں سے، آپ نے شاید Node.js کے بارے میں سنا ہوگا۔ ہم میں سے وہ لوگ جو جاوا اسکرپٹ کے آغاز سے لے کر آج تک موجود ہیں وہ جدید جاوا اسکرپٹ کی حالت میں یا تو ناقابل یقین حد تک خوفزدہ، حیران، یا دونوں ہیں، لیکن اس سے انکار نہیں کیا جا سکتا کہ جاوا اسکرپٹ سرورز پر بھی شمار کیے جانے کی طاقت بن گیا ہے۔ براؤزر کے طور پر. بہر حال، ہمارے پاس اب زبان میں مقامی 64 بٹ انٹیجرز بھی ہیں! یہ 64 بٹ فلوٹس میں محفوظ ہونے والی ہر چیز سے کہیں بہتر ہے!
ExpressJS شاید استعمال کرنے کے لیے سب سے آسان Node.js سرور ہے، لہذا ہم اپنے کاؤنٹر کی خدمت کے لیے ایک تیز اور گندا Node.js/ExpressJS ایپ کریں گے۔
/**********************************************************************
* 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}`));
یہ کوڈ اصل میں ازگر کے ورژنز کے مقابلے میں لکھنا آسان تھا، حالانکہ مقامی جاوا اسکرپٹ جب ایپلی کیشنز کے بڑے ہو جاتے ہیں تو اس کی بجائے غیر مؤثر ہو جاتا ہے، اور اسے درست کرنے کی تمام کوششیں جیسے TypeScript جلد ازگر سے زیادہ لفظی ہو جاتی ہیں۔
آئیے دیکھتے ہیں کہ یہ کیسے کام کرتا ہے!
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
آپ نے Node.js' کے بارے میں قدیم (انٹرنیٹ کے معیار کے لحاظ سے قدیم...) لوک کہانیاں سنی ہوں گی۔ رفتار، اور وہ کہانیاں زیادہ تر سچ ہیں اس شاندار کام کی بدولت جو گوگل نے V8 JavaScript انجن کے ساتھ کیا ہے۔ اس معاملے میں، اگرچہ ہماری کوئیک ایپ فلاسک اسکرپٹ سے بہتر کارکردگی کا مظاہرہ کرتی ہے، لیکن اس کی سنگل تھریڈڈ نوعیت کو سٹارلیٹ نائٹ کے ذریعے چلنے والے چار async عملوں سے شکست دی جاتی ہے جو کہ "Ni!" کہتی ہے۔
آئیے کچھ اور مدد حاصل کریں!
╰─➤ 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 │
└────┴──────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
ٹھیک ہے! اب یہ چار پر چار کی جنگ ہے! آئیے بینچ مارک!
╰─➤ 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
ابھی بھی سٹارلیٹ کی سطح پر بالکل نہیں، لیکن پانچ منٹ کی جاوا اسکرپٹ ہیک کے لیے یہ برا نہیں ہے۔ میری اپنی جانچ سے، اس اسکرپٹ کو درحقیقت ڈیٹا بیس انٹرفیسنگ کی سطح پر تھوڑا سا پیچھے رکھا جا رہا ہے کیونکہ نوڈ پوسٹگریس اتنا موثر نہیں ہے جتنا سائیکوپ جی ازگر کے لیے ہے۔ ڈیٹا بیس ڈرائیور کے طور پر sqlite پر سوئچ کرنے سے اسی ExpressJS کوڈ کے لیے فی سیکنڈ 3000 سے زیادہ درخواستیں موصول ہوتی ہیں۔
نوٹ کرنے والی اہم بات یہ ہے کہ Python کی سست رفتاری کے باوجود، ASGI فریم ورک دراصل کچھ کام کے بوجھ کے لیے Node.js حل کے ساتھ مسابقتی ہو سکتا ہے۔
تو اب، ہم پہاڑ کی چوٹی کے قریب پہنچ رہے ہیں، اور پہاڑ سے، میرا مطلب ہے چوہوں اور مردوں کے یکساں طور پر ریکارڈ کیے گئے اعلیٰ ترین بینچ مارک سکور۔
اگر آپ ویب پر دستیاب زیادہ تر فریم ورک بینچ مارکس کو دیکھیں گے، تو آپ دیکھیں گے کہ دو زبانیں ہیں جو سب سے اوپر حاوی ہوتی ہیں: C++ اور Rust۔ میں نے 90 کی دہائی سے C++ کے ساتھ کام کیا ہے، اور MFC/ATL ایک چیز ہونے سے پہلے میرے پاس اپنا Win32 C++ فریم ورک بھی تھا، اس لیے مجھے زبان کا کافی تجربہ ہے۔ کسی چیز کے ساتھ کام کرنے میں زیادہ مزہ نہیں آتا جب آپ اسے پہلے سے جانتے ہوں، لہذا ہم اس کے بجائے ایک Rust ورژن کرنے جا رہے ہیں۔ ;)
جہاں تک پروگرامنگ زبانیں جاتی ہیں، زنگ نسبتاً نیا ہے، لیکن یہ میرے لیے تجسس کا باعث بن گیا جب لینس ٹوروالڈس نے اعلان کیا کہ وہ زنگ کو لینکس کرنل پروگرامنگ زبان کے طور پر قبول کرے گا۔ ہمارے پرانے پروگرامرز کے لیے، یہ بالکل ایسا ہی ہے جیسا کہ یہ کہنے کے لیے کہ یہ نئی دھندلی نئی عمر کی ہپی چیزی امریکی آئین میں ایک نئی ترمیم ہونے جا رہی ہے۔
اب، جب آپ ایک تجربہ کار پروگرامر ہیں، تو آپ بینڈ ویگن پر اتنی تیزی سے کودنے کا رجحان نہیں رکھتے جتنی نوجوان لوگ کرتے ہیں، ورنہ آپ زبان یا لائبریریوں میں تیزی سے تبدیلیوں سے جل سکتے ہیں۔ (کوئی بھی جس نے انگولر جے ایس کا پہلا ورژن استعمال کیا ہے وہ جان لے گا کہ میں کس کے بارے میں بات کر رہا ہوں۔) زنگ ابھی بھی کسی حد تک تجرباتی ترقی کے مرحلے میں ہے، اور مجھے یہ مضحکہ خیز لگتا ہے کہ ویب پر بہت سے کوڈ کی مثالیں بھی نہیں ملتی ہیں۔ پیکیجز کے موجودہ ورژن کے ساتھ مزید مرتب کریں۔
تاہم، Rust ایپلی کیشنز کی طرف سے دکھائی گئی کارکردگی سے انکار نہیں کیا جا سکتا۔ اگر آپ نے کبھی کوشش نہیں کی۔ ripgrep یا fd-تلاش بڑے سورس کوڈ والے درختوں پر، آپ کو یقینی طور پر ان کو گھماؤ دینا چاہیے۔ وہ زیادہ تر لینکس ڈسٹری بیوشنز کے لیے بھی صرف پیکیج مینیجر سے دستیاب ہیں۔ آپ Rust... a کے ساتھ کارکردگی کے لیے لفظوں کا تبادلہ کر رہے ہیں۔ بہت ایک کے لیے فعل کی بہت کارکردگی کی.
Rust کے لیے مکمل کوڈ تھوڑا بڑا ہے، اس لیے ہم یہاں متعلقہ ہینڈلرز پر ایک نظر ڈالیں گے:
// =====================================================================
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
)))
}
یہ Python/Node.js ورژن سے کہیں زیادہ پیچیدہ ہے...
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
اور بہت زیادہ پرفارمنس!
Actix/deadpool_postgres کا استعمال کرنے والا ہمارا زنگ سرور ہماری سابقہ چیمپئن Starlette کو +125%، ExpressJS کو +362%، اور خالص PHP کو +1366% سے ہرا دیتا ہے۔ (میں قاری کے لیے ایک مشق کے طور پر Laravel ورژن کے ساتھ کارکردگی کے ڈیلٹا کو چھوڑ دوں گا۔)
میں نے محسوس کیا ہے کہ زنگ کی زبان سیکھنا بذات خود دوسری زبانوں کے مقابلے میں زیادہ مشکل ہے کیونکہ اس میں 6502 اسمبلی کے باہر جو کچھ بھی دیکھا ہے اس سے کہیں زیادہ گٹچز ہیں، لیکن اگر آپ کا رسٹ سرور 14 گنا بڑھ سکتا ہے۔ صارفین کو آپ کے پی ایچ پی سرور کے طور پر، پھر شاید ٹیکنالوجی کو تبدیل کرنے سے حاصل کرنے کے لیے کچھ ہے۔ اسی لیے Pafera فریم ورک کا اگلا ورژن Rust پر مبنی ہوگا۔ سیکھنے کا وکر اسکرپٹنگ زبانوں سے بہت زیادہ ہے، لیکن کارکردگی اس کے قابل ہوگی۔ اگر آپ Rust سیکھنے کے لیے وقت نہیں لگا سکتے، تو Starlette یا Node.js پر اپنے ٹیک اسٹیک کو بیس کرنا بھی کوئی برا فیصلہ نہیں ہے۔
پچھلے بیس سالوں میں، ہم سستی سٹیٹک ہوسٹنگ سائٹس سے لے کر LAMP اسٹیک کے ساتھ مشترکہ ہوسٹنگ تک VPSes کو AWS، Azure، اور دیگر کلاؤڈ سروسز تک کرائے پر لے گئے ہیں۔ آج کل، بہت سی کمپنیاں ڈیزائن کے فیصلے کرنے سے مطمئن ہیں جس کی بنیاد پر وہ اسے دستیاب یا سب سے سستا تلاش کر سکتی ہیں کیونکہ آسان کلاؤڈ سروسز کی آمد نے سست سرورز اور ایپلیکیشنز پر مزید ہارڈ ویئر پھینکنا آسان بنا دیا ہے۔ اس سے انہیں طویل مدتی تکنیکی قرضوں کی قیمت پر مختصر مدت کے بڑے فائدے ملے ہیں۔
70 سال پہلے سوویت یونین اور امریکہ کے درمیان زبردست خلائی دوڑ ہوئی تھی۔ سوویت یونین نے ابتدائی سنگ میلوں میں سے زیادہ تر جیتے۔ ان کے پاس سپوتنک میں پہلا سیٹلائٹ تھا، لائیکا میں خلا میں پہلا کتا، لونا 2 میں پہلا چاند خلائی جہاز، یوری گاگرین اور ویلنٹینا تریشکووا میں خلا میں پہلا مرد اور عورت، وغیرہ۔
لیکن وہ آہستہ آہستہ تکنیکی قرض جمع کر رہے تھے۔
اگرچہ سوویت ان کامیابیوں میں سے ہر ایک میں سب سے پہلے تھے، لیکن ان کے انجینئرنگ کے عمل اور اہداف انہیں طویل مدتی فزیبلٹی کے بجائے قلیل مدتی چیلنجوں پر توجہ مرکوز کرنے پر مجبور کر رہے تھے۔ ہر بار جب وہ چھلانگ لگاتے ہیں تو وہ جیت جاتے تھے، لیکن وہ زیادہ تھکے ہوئے اور آہستہ ہوتے جا رہے تھے جب کہ ان کے مخالفین فائنل لائن کی طرف مسلسل قدم اٹھاتے رہے۔
ایک بار جب نیل آرمسٹرانگ نے براہ راست ٹیلی ویژن پر چاند پر اپنے تاریخی قدم رکھے تو امریکیوں نے اس کی قیادت کی، اور پھر سوویت پروگرام کے زوال کے بعد وہیں ٹھہر گئے۔ یہ آج کی کمپنیوں سے مختلف نہیں ہے جنہوں نے طویل سفر کے لیے مناسب عادات اور حکمت عملی تیار کرنے میں ناکام رہتے ہوئے اگلی بڑی چیز، اگلی بڑی ادائیگی، یا اگلی بڑی ٹیک پر توجہ مرکوز کی ہے۔
مارکیٹ میں سب سے پہلے ہونے کا مطلب یہ نہیں ہے کہ آپ اس مارکیٹ میں غالب کھلاڑی بن جائیں گے۔ متبادل طور پر، چیزوں کو درست کرنے کے لیے وقت نکالنا کامیابی کی ضمانت نہیں دیتا، لیکن یقینی طور پر آپ کی طویل مدتی کامیابیوں کے امکانات کو بڑھاتا ہے۔ اگر آپ اپنی کمپنی کے لیے ٹیک لیڈ ہیں، تو اپنے کام کے بوجھ کے لیے صحیح سمت اور ٹولز کا انتخاب کریں۔ مقبولیت کو کارکردگی اور کارکردگی کی جگہ نہ لینے دیں۔
زنگ، ایکسپریس جے ایس، فلاسک، اسٹارلیٹ اور خالص پی ایچ پی اسکرپٹس پر مشتمل 7z فائل ڈاؤن لوڈ کرنا چاہتے ہیں؟
مصنف کے بارے میں |
|
![]() |
جم 90 کی دہائی کے دوران IBM PS/2 واپس ملنے کے بعد سے پروگرامنگ کر رہا ہے۔ آج تک، وہ اب بھی ہاتھ سے HTML اور SQL لکھنے کو ترجیح دیتا ہے، اور اپنے کام میں کارکردگی اور درستگی پر توجہ دیتا ہے۔ |