2015-07-02 16 views
5

मैं गीवेंट और websockets के साथ खेल रहा हूँ।gevent-websocket तुल्यकालिक क्यों है?

from gevent.pywsgi import WSGIServer 
from geventwebsocket.handler import WebSocketHandler 
from gevent import sleep 
from datetime import datetime 
def app(environ, start_response): 
    ws = environ['wsgi.websocket'] 
    while True: 
     data = ws.receive() 
     print('{} got data "{}"'.format(
      datetime.now().strftime('%H:%M:%S'), data)) 
     sleep(5) 
     ws.send(data) 

server = WSGIServer(("", 10004), app, 
    handler_class=WebSocketHandler) 
server.serve_forever() 

और ग्राहक: यह एक सरल गूंज सर्वर है

<html> 
    <body> 
     <button type="button" id="push_data">Push</button> 
    </body> 
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.js"></script> 
    <script> 
     var ws = new WebSocket("ws://localhost:10004"); 
     ws.onmessage = function(evt) { 
      console.log(evt) 
     }; 
     $('#push_data').click(function(){ 
      console.log('sending data...'); 
      ws.send('sample data'); 
     }); 
    </script> 
</html> 
gevent मैं कई अतुल्यकालिक रूप से डेटा की सेवा greenlets के लिए उम्मीद कर रहा था की वजह से

; जो है, अगर मैं कई बार WebSocket के लिए कुछ डेटा धक्का दिया (जल्दी से पुश बटन पर क्लिक), मैं यह सब वापस एक साथ इंतजार कर के 5 सेकंड के बाद करने के लिए उम्मीद कर रहा था।

18:28:07 got data "sample data" 
18:28:12 got data "sample data" 
18:28:17 got data "sample data" 
18:28:22 got data "sample data" 
18:28:27 got data "sample data" 

कारण है कि यह मेरे डेटा तुल्यकालिक प्राप्त करता है, हर 5 सेकंड रोक:

हालांकि, कोई फर्क नहीं पड़ता कितनी तेजी से मैं पुश बटन पर क्लिक करें, यह क्या मैं कंसोल में मिल रहा है? मैं इसे एसिंक्रोनस सर्वर में कैसे बदलूं? क्योंकि अपने स्वयं के कोड सिंक्रोनस होता है

उत्तर

6

व्यवहार तुल्यकालिक है। गीवेंट एक इवेंट लूप का उपयोग कर केवल एक कोरआउट लाइब्रेरी है। यह सिंक्रोनस कोड को एसिंक्रोनस कोड में जादुई रूप से नहीं बदलता है। सर्वर कनेक्शन (अनुरोध के अनुसार नहीं) प्रति एक greenlet अंडे http://www.gevent.org/servers.html

यह कहा जाता है:

कृपया पर दस्तावेज़ पर एक नजर है। इसलिए एक ही कनेक्शन के लिए एकाधिक अनुरोधों का निष्पादन क्रमबद्ध है।

आप समवर्ती एक ही कनेक्शन के लिए एक से अधिक अनुरोध हैंडल करना चाहते हैं, तो आप नए greenlets अंडे, या greenlets का एक पूल के प्रसंस्करण को सौंपने के लिए की जरूरत है।

import gevent 
from gevent.pywsgi import WSGIServer 
from gevent.lock import Semaphore 
from geventwebsocket.handler import WebSocketHandler 
from datetime import datetime 

def process(ws,data,sem): 
    print('{} got data "{}"'.format(datetime.now().strftime('%H:%M:%S'), data)) 
    gevent.sleep(5) 
    with sem: 
     ws.send(data) 

def app(environ, start_response): 
    ws = environ['wsgi.websocket'] 
    sem = Semaphore() 
    while True: 
     data = ws.receive() 
     gevent.spawn(process,ws,data,sem) 

server = WSGIServer(("", 10004), app,handler_class=WebSocketHandler) 
server.serve_forever() 

नोट सेमाफोर की उपस्थिति:

यहाँ एक उदाहरण (प्रत्येक अनुरोध पर एक greenlet को उत्पन्न करने) है। क्योंकि प्रसंस्करण समवर्ती है, सॉकेट पर एक ही समय में दो समवर्ती ग्रीनलेट्स को लिखने के लिए इसकी आवश्यकता होती है, जिसके परिणामस्वरूप दूषित संदेश होते हैं।

अंतिम बिंदु, इस कार्यान्वयन के साथ, इस बात की कोई गारंटी नहीं है कि अनुरोध अनुरोधों के क्रम में भेजे जाएंगे। डेटा = ws.receive()

यहाँ क्या हो रहा है अपने WebSocket अब एक ही कनेक्शन के लिए प्रतीक्षा कर रहा है है पूरे एप्लिकेशन सिर्फ बाहर लटक जबकि:

+1

क्या गीवेंट के साथ बंदर पैचिंग "जादूगर रूप से सिंक्रोनस कोड को एसिंक्रोनस कोड में बदलता है"? – FullStack

+2

केवल तभी यदि आपके पास एकाधिक ग्रीनलेट और कनेक्शन हैं। यदि कोड एक ही ग्रीनलेट से एक कनेक्शन से निपट रहा है, तो गीवेंट का कोरआउट तंत्र मदद नहीं करेगा।दूसरे शब्दों में, जादू केवल तब होता है जब आप इसमें विश्वास करते हैं, और तदनुसार अपना कोड बनाते हैं ;-) –

0

वास्तविक समस्या यह है।

आप दो समाधान है, या तो ws.receive करने के लिए एक समय समाप्ति जोड़ने() या इसे सेट अप एक उच्च स्तरीय आवेदन के रूप में:

from geventwebsocket import WebSocketServer, WebSocketApplication, Resource 

class EchoApplication(WebSocketApplication): 
    def on_open(self): 
     print "Connection opened" 

    def on_message(self, message): 
     self.ws.send(message) 

    def on_close(self, reason): 
     print reason 

WebSocketServer(('', 8000), Resource({'/': EchoApplication}).serve_forever() 

के रूप में यहाँ exampled: https://pypi.python.org/pypi/gevent-websocket/

यह तो अपने सेटअप होगा पूरी तरह से async प्रक्रिया, इस प्रकार भेजने और प्राप्त करने के लिए एक ही संसाधन के लिए प्रतिस्पर्धा नहीं करेंगे।

संबंधित मुद्दे