2011-09-19 7 views
5
यहाँ

में सुन घटना को लागू करने के लिए कैसे मेरी समस्या है:पीएचपी

while(no_changes){ 
    usleep(100000); 
    //check for changes 
} 
: मैं एक स्क्रिप्ट (यह comet.php कॉल) जो एक AJAX ग्राहक स्क्रिप्ट के द्वारा requsted जाता है और एक बदलाव के लिए इंतजार इस तरह से होने की राशि

मुझे यह बहुत पसंद नहीं है, यह बहुत स्केलेबल नहीं है और यह (imho) "खराब अभ्यास" मैं इस व्यवहार को एक सेमफोर (?) या फिर भी समवर्ती प्रोग्रामिंग तकनीक के साथ सुधारना चाहता हूं। क्या आप कृपया इसे संभालने के बारे में कुछ सुझाव दे सकते हैं? (मुझे पता है, यह एक संक्षिप्त उत्तर नहीं है, लेकिन एक प्रारंभिक बिंदु पर्याप्त होगा।)

संपादित: LibEvent के बारे में क्या?

+0

आप प्राप्त करने के लिए कोशिश कर रहे हैं? सामान्य तरीका यह है कि ग्राहक परिवर्तनों की जांच के लिए समय-समय पर स्क्रिप्ट को कॉल करें। क्या कोई कारण है कि आप इसे सर्वर-साइड क्यों करना चाहते हैं? – JJJ

+3

PHP वास्तव में ऐसी भाषा नहीं है जिसका उपयोग आपको कॉमेट के लिए करना चाहिए। नोड का प्रयोग करें।जेएस या कुछ और जो असीमित रूप से काम करता है (उदाहरण के लिए पायथन टॉरनाडो या ग्रीनलेट)। थ्रेड/प्रोसेस-आधारित वेबसर्वर पर चल रहे PHP का उपयोग करके आपके पास एक विशाल ओवरहेड है। – ThiefMaster

+0

@ जुहाना, कारण परिवर्तन के लिए आवधिक जांच से बचने का कारण है और 'रिवर्स-एजेक्स' समाधान है। @thiefMaster मैं जानता हूँ कि वहाँ वहाँ कुछ कोमेट सर्वर समाधान कर रहे हैं, लेकिन मैं सच में लगता है कि एक php बैकएंड संभव हो सकता है, और जब तक मैं PHP में अपने व्यवसाय लॉगिन बारे में यह वास्तव में बेहतर कोई अन्य भाषा से परहेज कोड में में पुनर्लेखन के लिए नहीं होगा दोहराव। क्या आप कृपया मुझे समझा सकते हैं कि क्यों एक PHP धूमकेतु बैकएंड ओवरहेडिंग होगा? – ArtoAle

उत्तर

12

आप ZeroMQ का उपयोग करके इस समस्या को हल कर सकते हैं।

ज़ीरोएमक्यू एक ऐसी लाइब्रेरी है जो चीजों (धागे, प्रक्रियाओं और यहां तक ​​कि अलग मशीनों) को एक साथ जोड़ने के लिए सुपरचार्ज किए गए सॉकेट प्रदान करती है।

मैं तुम्हें ग्राहक के लिए सर्वर से डेटा पुश करने के लिए कोशिश कर रहे हैं मान। ठीक है, ऐसा करने के लिए एक अच्छा तरीका EventSource API (polyfills available) का उपयोग कर रहा है।

client.js

EventSource के माध्यम से stream.php को जोड़ता है।

var stream = new EventSource('stream.php'); 

stream.addEventListener('debug', function (event) { 
    var data = JSON.parse(event.data); 
    console.log([event.type, data]); 
}); 

stream.addEventListener('message', function (event) { 
    var data = JSON.parse(event.data); 
    console.log([event.type, data]); 
}); 

router.php

यह एक लंबी चलने वाली प्रक्रिया है कि भेजे गए संदेशों के लिए सुनता है और कोई सुन रहा करने के लिए उन्हें बाहर भेजता है।

<?php 

$context = new ZMQContext(); 

$pull = $context->getSocket(ZMQ::SOCKET_PULL); 
$pull->bind("tcp://*:5555"); 

$pub = $context->getSocket(ZMQ::SOCKET_PUB); 
$pub->bind("tcp://*:5556"); 

while (true) { 
    $msg = $pull->recv(); 
    echo "publishing received message $msg\n"; 
    $pub->send($msg); 
} 

stream.php

साइट को कनेक्ट करने प्रत्येक उपयोगकर्ता अपने ही stream.php हो जाता है। यह स्क्रिप्ट लंबी दौड़ रही है और राउटर से किसी भी संदेश की प्रतीक्षा कर रही है। एक बार यह एक नया संदेश प्राप्त हो जाने पर, यह इवेंटसोर्स प्रारूप में इस संदेश को आउटपुट करेगा।

<?php 

$context = new ZMQContext(); 

$sock = $context->getSocket(ZMQ::SOCKET_SUB); 
$sock->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, ""); 
$sock->connect("tcp://127.0.0.1:5556"); 

set_time_limit(0); 
ini_set('memory_limit', '512M'); 

header("Content-Type: text/event-stream"); 
header("Cache-Control: no-cache"); 

while (true) { 
    $msg = $sock->recv(); 
    $event = json_decode($msg, true); 
    if (isset($event['type'])) { 
     echo "event: {$event['type']}\n"; 
    } 
    $data = json_encode($event['data']); 
    echo "data: $data\n\n"; 
    ob_flush(); 
    flush(); 
} 

सभी उपयोगकर्ताओं को संदेश भेजने के लिए, बस उन्हें राउटर पर भेजें। राउटर तब उस संदेश को सभी सुनने वाली धाराओं में वितरित करेगा। यहां एक उदाहरण दिया गया है:

<?php 

$context = new ZMQContext(); 

$sock = $context->getSocket(ZMQ::SOCKET_PUSH); 
$sock->connect("tcp://127.0.0.1:5555"); 

$msg = json_encode(array('type' => 'debug', 'data' => array('foo', 'bar', 'baz'))); 
$sock->send($msg); 

$msg = json_encode(array('data' => array('foo', 'bar', 'baz'))); 
$sock->send($msg); 

यह साबित करना चाहिए कि आपको रीयलटाइम प्रोग्रामिंग करने के लिए node.js की आवश्यकता नहीं है। PHP इसे ठीक से संभाल सकता है।

इसके अलावा, socket.io ऐसा करने का एक बहुत अच्छा तरीका है। और आप आसानी से ZeroMQ के माध्यम से अपने PHP कोड में socket.io से कनेक्ट कर सकते हैं।

भी

+2

कृपया ध्यान दें: मैंने हाल ही में कुछ मानक किए हैं। कुछ बिंदु पर यह बहुत अच्छी तरह से स्केल नहीं करता है। मैंने कुछ सौ जुड़े ग्राहकों के साथ थोड़े समय में कुछ हज़ार संदेश भेजने की कोशिश की। यदि आप अपाचे का उपयोग कर रहे हैं, तो थ्रेड के बीच संदर्भ स्विचिंग की मात्रा के कारण यह धीमा हो जाएगा। कुछ बिंदु पर नोड या nginx-push-stream मॉड्यूल ऐसा करने के लिए बेहतर उपकरण होगा। फिर भी, यह PHP के साथ संभव है और यह काम करता है। – igorw

+1

बस इसके साथ-साथ बहुत वर्णनात्मक उदाहरण की आसानी और सादगी से प्यार करें। लाइन के नीचे 6 साल और अभी तक एक सरल उत्तर उत्तर। धन्यवाद! –

4

यह वास्तव में इस बात पर निर्भर करता है कि आप अपने सर्वर साइड स्क्रिप्ट में क्या कर रहे हैं। ऐसी कुछ स्थितियां हैं जिनमें आपके ऊपर कोई काम करने के अलावा कोई विकल्प नहीं है।

हालांकि, अगर आप ऐसा कुछ कर रहे हैं जिसमें किसी फ़ंक्शन को कॉल करना शामिल है जो कुछ होने तक अवरुद्ध हो जाए, तो आप usleep() कॉल के बजाय रेसिंग से बचने के लिए इसका उपयोग कर सकते हैं (जो आईएमएचओ हिस्सा है जिसे "बुरा अभ्यास माना जाएगा ")।

कहें कि आप किसी फ़ाइल या किसी अन्य प्रकार की स्ट्रीम से डेटा की प्रतीक्षा कर रहे थे जो ब्लॉक करता है। आप ऐसा कर सकता है:

while (($str = fgets($fp)) === FALSE) continue; 
// Handle the event here 

वास्तव में, पीएचपी इस तरह सामान करने के लिए गलत भाषा है। लेकिन हालात हैं (मुझे पता है क्योंकि मैंने खुद से निपटाया है) जहां PHP एकमात्र विकल्प है।

+1

वास्तव में के लिए जाँच के आधार पर, मैं NOOP जबकि निकाल कर सीपीयू भूमि के ऊपर कम करने के लिए चाहते हैं (यही कारण है कि वहाँ usleep() कॉल है) – ArtoAle

+2

@ArtoAle आप कर सकते हैं ' PHP में किसी प्रकार के लूप के बिना किसी ईवेंट की प्रतीक्षा न करें - इसमें कोई इवेंट हैंडलर नहीं हैं जैसे कि जावास्क्रिप्ट। लेकिन उपर्युक्त रूप में उल्लिखित करके, आप चेक-नींद-चेक-नींद-जांच के बजाय 'fgets()' कॉल प्रतीक्षा कर रहे हैं ... आपके उदाहरण में, यदि घटना 'नींद() के दौरान होती है आपको इसे संभालने से पहले नींद के अंत की प्रतीक्षा करनी होगी। लूप स्थिति के रूप में (अवरुद्ध) चेक का उपयोग करके, 'fgets() 'जैसे ही घटना हुई है तुरंत आप लौटते हैं और आप इसे तुरंत संभाल सकते हैं। – DaveRandom

+0

ठीक है, आप सही हैं। मुद्दा यह है कि [सिस्टम वी आईपीसी] (http://www.php.net/manual/en/intro.sem.php) के साथ मैं अवरुद्ध कॉल प्राप्त सेमाफोर को (जो परिणाम एक ही समाधान आप प्रस्तावित में) का उपयोग कर सकते है समस्या यह है कि मुझे वास्तव में नहीं पता कि सेमेफोर का उपयोग कैसे करें "घटना-जैसे" अनुप्रयोग व्यवहार – ArtoAle

2

जितना मुझे PHP पसंद है, मुझे यह कहना होगा कि PHP इस कार्य के लिए सबसे अच्छा विकल्प नहीं है। Node.js इस तरह की चीज़ के लिए बहुत बेहतर है और यह वास्तव में अच्छा है। यदि आपके पास जेएस ज्ञान है तो इसे लागू करना भी बहुत आसान है।

अब, यदि आप सीपीयू चक्र बर्बाद नहीं करना चाहते हैं, तो आपको एक PHP स्क्रिप्ट बनाना होगा जो किसी निश्चित पोर्ट पर किसी प्रकार के सर्वर से कनेक्ट होगा। निर्दिष्ट सर्वर को चुने हुए बंदरगाह पर कनेक्शन के लिए सुनना चाहिए और जो कुछ भी आप जांचना चाहते हैं उसके लिए प्रत्येक एक्स की मात्रा जांचें (उदाहरण के लिए नई पोस्ट के लिए डीबी प्रविष्टियां) और फिर यह प्रत्येक प्रविष्टि क्लाइंट को संदेश भेजता है कि नई प्रविष्टि तैयार है।

अब, यह PHP में इस घटना कतार वास्तुकला लागू करने के लिए है कि मुश्किल नहीं है, लेकिन यह आप सचमुच 5 मिनट काफ़ी होगा Node.js और Socket.IO के साथ ऐसा करने में चिंता है कि क्या यह के बहुमत में काम करेंगे के बिना, ब्राउज़रों।

0

मैं यहां सर्वसम्मति से सहमत हूं कि PHP यहां सबसे अच्छा समाधान नहीं है। आपको अपने सर्वर से अपने ग्राहकों से डेटा वितरित करने की इस असीमित समस्या के समाधान के लिए आपको वास्तव में समर्पित realtime technologies पर देखने की आवश्यकता है। ऐसा लगता है कि आप HTTP-Long Polling को लागू करने का प्रयास कर रहे हैं जो क्रॉस-ब्राउज़र को हल करने के लिए एक आसान बात नहीं है। कॉमेट उत्पादों के डेवलपर्स द्वारा कई बार इसका सामना किया गया है, इसलिए मैं सुझाव दूंगा कि आप धूमकेतु समाधान देखें, या पुराने ब्राउज़र के लिए फ़ॉलबैक समर्थन के साथ वेबसाकेट समाधान को बेहतर बनाएं।

मैं सुझाव दूंगा कि आप PHP को वेब एप्लिकेशन कार्यक्षमता दें जो कि यह अच्छा है और आपके रीयलटाइम, ईवेंट, एसिंक्रोनस कार्यक्षमता के लिए एक समर्पित समाधान चुनें।

0

देखें आप एक वास्तविक समय पुस्तकालय की जरूरत है।

एक उदाहरण Ratchet http://socketo.me/

बात यह है कि पब उप का ख्याल सीमा यहाँ पीएचपी भी परिवर्तनशील डेटा आरंभ करने के लिए एक होने की जरूरत है वह यह है कि लेता है http://socketo.me/docs/wamp

पर चर्चा कर रहा है।

दूसरे शब्दों में यह जादूगर रूप से आपको सदस्यता लेने देता है जब MySQL अद्यतन किया जाता है। लेकिन अगर आप MySQL- सेटिंग कोड को संपादित कर सकते हैं तो आप वहां प्रकाशित भाग जोड़ सकते हैं।