python异步回调函数的实现

来源:互联网 发布:mac怎么查看java版本 编辑:程序博客网 时间:2024/05/15 13:22

说到异步回调函数的应用,最经典的就是ajax。

首先我们回想一下ajax是如何工作的。

variable=new XMLHttpRequest();xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("myDiv").innerHTML=xmlhttp.responseText;}}xmlhttp.open("GET","test1.txt",true);xmlhttp.send();

这是一个经典的ajax使用方式,创建对象后为对象绑定回调函数,然后发送请求到远程服务器,由于是异步,所以继续往下执行,当远程服务器返回的时候,调用绑定的回调函数。

这里我们看到浏览器为我们做了一些事情,1、发送请求到远程服务器,2、监听远程服务器的返回,并且根据返回找到了对应的回调函数,然后执行。

实际上这里可以分成3个模型,一是脚本执行流程,二是浏览器底层,三是远程服务器。

而且为了实现python的异步回调函数也需要这三个模型。

根据自己的需要,我做了3个模型。

1是监听器listener,相当于浏览器底层。
作用是:监听7800端口
       负责接收来自YoSQL服务器的回复
       然后解析协议,得到回调函数的ID,通知逻辑进程执行回调函数
       从YoSQL服务器发来的协议格式是“[id]message”,字符串表示

2是逻辑进程main,相当于脚本执行流程

作用是:
执行逻辑
发送消息和回调函数ID到YoSQL服务器,端口3316
执行逻辑
当收到YoSQL服务器的回复的时候执行回调函数
执行逻辑
。。。。
从逻辑进程发送到YoSQL服务器的协议是“[id]message”,字符串表示

3是YoSQL服务器,相当于远程服务器

作用是:
监听3316端口
接收消息,解析协议,休眠2秒,回复监听器7800端口


YoSQL是一个独立的进程。为了简化开发,我将listener和main放到一个进程里面,分为2个线程来执行。当然你也可以用C来实现listener,C和python能够共享对象,实现起来也方便。

下面直接贴代码吧。

YoSQL代码

#-*-coding:utf-8-*-from socket import *import timedef main():HOST = ""PORT = 3316BUFSIZE = 1024ADDR = (HOST, PORT)tcpSerSock = socket(AF_INET, SOCK_STREAM)tcpSerSock.bind(ADDR)tcpSerSock.listen(5)print "YoSQL bind port %d ,starting ...." % PORTwhile  1:print 'waiting for connection ...'tcpCliSock, addr = tcpSerSock.accept()print '...connected from:',addrwhile 1:try:data = tcpCliSock.recv(BUFSIZE)if not data:breakprint 'data = %s' % datai = data.find('[')j = data.find(']')if i!=-1 and j!=-1:sFuncId = data[i+1:j]message = data[j+1:]time.sleep(2)SendToListener("[%s] echo" % sFuncId)except Exception, e:print ebreaktcpCliSock.close()tcpSerSock.close()def SendToListener(message):listenerSock = socket(AF_INET, SOCK_STREAM)listenerSock.connect(('localhost',7800))listenerSock.send(message)listenerSock.close()print 'send to listener: %s' % messageif __name__ == '__main__':main()


listener和main代码:

#-*-coding:utf-8-*-import threadingimport timefrom socket import *lCallback = {}iFuncId = 0 def StartListener():global iFuncIdglobal lCallbackHOST = ""PORT = 7800BUFSIZE = 1024ADDR = (HOST, PORT)tcpSerSock = socket(AF_INET, SOCK_STREAM)tcpSerSock.bind(ADDR)tcpSerSock.listen(5)print "Listener bind port %d ,starting ...." % PORTwhile 1:print 'waiting for connection ...'tcpCliSock, addr = tcpSerSock.accept()print '...connected from:',addrwhile 1:try:data = tcpCliSock.recv(BUFSIZE)if not data:breakprint 'data = %s' % datai = data.find('[')j = data.find(']')if i!=-1 and j!=-1:iFuncId = int(data[i+1:j])message = data[j+1:]func = lCallback.get(iFuncId,None)if func:func()del lCallback[iFuncId]except Exception,e:print ebreaktcpCliSock.close()tcpSerSock.close()def MyCallback():print 'callback called !!!!!!!!!!'def Send(callback,message):global iFuncIdglobal lCallbacklCallback[iFuncId] = callbacklistenerSock = socket(AF_INET, SOCK_STREAM)listenerSock.connect(('localhost',3316))listenerSock.send("[%d] %s" % (iFuncId,message))listenerSock.close()iFuncId += 1print 'send message to YoSQL : %s'%messagedef DoSomeThing():print '......DoSomeThing......'if __name__ == '__main__':t = threading.Thread(target=StartListener)t.setDaemon(True)t.start()# t.join()DoSomeThing()DoSomeThing()Send(MyCallback,"hahaha")i = 0while i < 20:i+= 1DoSomeThing()try:time.sleep(0.5)except Exception,e:print ebreak# t.join(2)print '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'

下面是执行结果图:


可以看到发送信息到远程服务器之后主逻辑继续往下执行,并没有阻塞,当远程服务器返回的时候回调函数被执行了


原创粉丝点击