说到异步回调函数的应用,最经典的就是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 time
def main():
HOST = ""
PORT = 3316
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
print "YoSQL bind port %d ,starting ...." % PORT
while 1:
print 'waiting for connection ...'
tcpCliSock, addr = tcpSerSock.accept()
print '...connected from:',addr
while 1:
try:
data = tcpCliSock.recv(BUFSIZE)
if not data:
break
print 'data = %s' % data
i = 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 e
break
tcpCliSock.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' % message
if __name__ == '__main__':
main()
#-*-coding:utf-8-*-
import threading
import time
from socket import *
lCallback = {}
iFuncId = 0
def StartListener():
global iFuncId
global lCallback
HOST = ""
PORT = 7800
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
print "Listener bind port %d ,starting ...." % PORT
while 1:
print 'waiting for connection ...'
tcpCliSock, addr = tcpSerSock.accept()
print '...connected from:',addr
while 1:
try:
data = tcpCliSock.recv(BUFSIZE)
if not data:
break
print 'data = %s' % data
i = 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 e
break
tcpCliSock.close()
tcpSerSock.close()
def MyCallback():
print 'callback called !!!!!!!!!!'
def Send(callback,message):
global iFuncId
global lCallback
lCallback[iFuncId] = callback
listenerSock = socket(AF_INET, SOCK_STREAM)
listenerSock.connect(('localhost',3316))
listenerSock.send("[%d] %s" % (iFuncId,message))
listenerSock.close()
iFuncId += 1
print 'send message to YoSQL : %s'%message
def DoSomeThing():
print '......DoSomeThing......'
if __name__ == '__main__':
t = threading.Thread(target=StartListener)
t.setDaemon(True)
t.start()
# t.join()
DoSomeThing()
DoSomeThing()
Send(MyCallback,"hahaha")
i = 0
while i < 20:
i+= 1
DoSomeThing()
try:
time.sleep(0.5)
except Exception,e:
print e
break
# t.join(2)
print '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'
下面是执行结果图:
可以看到发送信息到远程服务器之后主逻辑继续往下执行,并没有阻塞,当远程服务器返回的时候回调函数被执行了