多线程和代理会增加 30 秒的延迟。我可以做什么来避免

发布于 2024-10-18 04:48:54 字数 4308 浏览 1 评论 0原文

我使用 PyQt、QThreads 和 couchdb-python 与本地 LAN 上的 couchDB 实例进行通信。

为了测试多线程在网络速度慢的情况下是否可以工作,我在 GUI 和沙发之间放置了一个代理。

网络已记录。日志以 That 开头

13:52:46.303 (1) send: HEAD /cubic HTTP/1.1CRLFHost: localhost:5981CRLFContent-Length: 0CRLFAccept: application/jsonCRLFUser-Agent: CouchDB-Python/0.8CRLFCRLF

13:52:46.308 (1) recv: HTTP/1.1 200 OKCRLFServer: CouchDB/1.0.1 (Erlang OTP/R13B)CRLFDate: Mon, 21 Feb 2011 13:47:18 GMTCRLFContent-Type: application/jsonCRLFContent-Length: 219CRLFCache-Control: must-revalidateCRLFCRLF
13:53:16.312 (1) recv: link closed
13:53:16.319 (2) send: GET /cubic/_design/Company/_view/by_name HTTP/1.1CRLFHost: localhost:5981CRLFContent-Length: 0CRLFAccept: application/jsonCRLFUser-Agent: CouchDB-Python/0.8CRLFCRLF
13:53:16.330 (2) recv: HTTP/1.1 200 OKCRLFTransfer-Encoding: chunkedCRLFServer: CouchDB/1.0.1 (Erlang OTP/R13B)CRLFEtag: "243QGZGN1ETGA4VN9H1OMB86Z"CRLFDate: Mon, 21 Feb 2011 13:47:48 GMTCRLFContent-Type: application/jsonCRLFCache-Control: must-revalidateCRLFCRLF
13:53:16.331 (2) recv: a0CRLF{"total_rows":9,"offset":0,"rows":[CRLF{"id":"c182c1a2f71c3547ccee45556300770e","key":["A first Company","231","345 East of Eden" ,"Manchester",null],"value":null}CRLF
13:53:16.332 (2) recv: 77CRLF,CRLF{"id":"c182c1a2f71c3547ccee455563001254","key":["C-U-B","1","9-11 March Business Centre","March",null],"value":null}CRLF72CRLF,CRLF{"id":"421261e8a3311c356c4900185800d976","key":"Four","104","4 Fourth street","Four Score",null],"value":null}CRLF74CRLF,CRLF{"id":"c182c1a2f71c3547ccee455563003de8","key":["Fred Smith","431","30 High street","Somehow",null],"value":null}CRLF
13:53:16.334 (2) recv: 83CRLF,CRLF{"id":"7bc7f2014593d108b5b681fe03002ad6","key":["Ian Hobson","1002","31 Sheerwater Dr","Northampton, Nhants",null],"value":null}CRLF76CRLF,CRLF{"id":"c182c1a2f71c3547ccee455563003139","key":["Julie Bloggs","302","30 Back Lane","Somewhere",null],"value":null}CRLF7cCRLF,CRLF{"id":"c182c1a2f71c3547ccee455563002e87","key": "Kingfisher Group","323","33 Westmister Rd","Londonx",null],"value":null}CRLF
13:53:16.335 (2) recv: 7aCRLF,CRLF{"id":"c182c1a2f71c3547ccee455563005894","key":["New Company","212","34 Back Street","Another Town",null],"value":null}CRLF72CRLF,CRLF{"id":"421261e8a3311c356c4900185800d7e2","key":["Three","103","3 High Street","Liverpool 8",null],"value":null}CRLF4CRLFCRLF]}CRLF1CRLFLFCRLF0CRLFCRLF
13:53:46.337 (2) recv: link closed

,与预期完全一致,只是在 13:52:46.308 打开数据库后有 30 秒的延迟,同时 recv 链接超时。直到发生这种情况,代码才能打开在 13:53:16.319 发生的视图,

但是代理使用不同的线程{(2)而不是(1)}。应用程序部分在没有代理的情况下工作得很好,所以我怀疑代理。

代理代码基于microproxy,下面

import re, sys, datetime
import socket 
import threading 
PORT = 5981
class ConnectionThread(threading.Thread): 
    def __init__(self, (conn,addr),id): 
        self.conn = conn 
        self.addr = addr
        self.id = id
        threading.Thread.__init__(self)

    def report(self,data,dir):
        txt = data.replace("\n",'LF')
        txt = txt.replace("\r",'CR')
        now = datetime.datetime.now()
        print "%s (%s) %s: %s" % (now.isoformat()[11:23],self.id,dir,txt)      

    def run(self): 
        data = self.conn.recv(1024*1024) 
        request = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        request.connect(('192.168.0.1',5984)) 
        self.report(data,'send')
        request.send(data) 
        while True: 
            temp = request.recv(1024) 
            if ('' == temp):
                self.report('link closed','recv')
                break 
            self.report(temp,'recv')
            self.conn.send(temp)
        self.conn.close()

class ProxyThread(threading.Thread): 
    def __init__(self, port): 
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        self.sock.bind(('localhost', port))
        self.count = 1
        threading.Thread.__init__(self) 
    def run(self): 
        self.sock.listen(3) 
        while True:
            temp = ConnectionThread(self.sock.accept(),self.count)
            temp.start()   # each message handled in own thread
            self.count += 1
if __name__ == "__main__": 
    print "Starting a proxy on port", PORT
    proxy = ProxyThread(PORT) 
    proxy.run() 

打开数据库的请求和视图的请求都是在同一个(非GUI)中进行的 线。为什么会发生延迟?

我怎样才能改变事情而不是这样呢?

I am usign PyQt, QThreads and couchdb-python to talk to a couchDB instance on the local LAN.

To test that the multithreading will work if the networking is slow, I have placed a proxy between the GUI and couch.

The networking is logged. The log starts off with

13:52:46.303 (1) send: HEAD /cubic HTTP/1.1CRLFHost: localhost:5981CRLFContent-Length: 0CRLFAccept: application/jsonCRLFUser-Agent: CouchDB-Python/0.8CRLFCRLF

13:52:46.308 (1) recv: HTTP/1.1 200 OKCRLFServer: CouchDB/1.0.1 (Erlang OTP/R13B)CRLFDate: Mon, 21 Feb 2011 13:47:18 GMTCRLFContent-Type: application/jsonCRLFContent-Length: 219CRLFCache-Control: must-revalidateCRLFCRLF
13:53:16.312 (1) recv: link closed
13:53:16.319 (2) send: GET /cubic/_design/Company/_view/by_name HTTP/1.1CRLFHost: localhost:5981CRLFContent-Length: 0CRLFAccept: application/jsonCRLFUser-Agent: CouchDB-Python/0.8CRLFCRLF
13:53:16.330 (2) recv: HTTP/1.1 200 OKCRLFTransfer-Encoding: chunkedCRLFServer: CouchDB/1.0.1 (Erlang OTP/R13B)CRLFEtag: "243QGZGN1ETGA4VN9H1OMB86Z"CRLFDate: Mon, 21 Feb 2011 13:47:48 GMTCRLFContent-Type: application/jsonCRLFCache-Control: must-revalidateCRLFCRLF
13:53:16.331 (2) recv: a0CRLF{"total_rows":9,"offset":0,"rows":[CRLF{"id":"c182c1a2f71c3547ccee45556300770e","key":["A first Company","231","345 East of Eden" ,"Manchester",null],"value":null}CRLF
13:53:16.332 (2) recv: 77CRLF,CRLF{"id":"c182c1a2f71c3547ccee455563001254","key":["C-U-B","1","9-11 March Business Centre","March",null],"value":null}CRLF72CRLF,CRLF{"id":"421261e8a3311c356c4900185800d976","key":"Four","104","4 Fourth street","Four Score",null],"value":null}CRLF74CRLF,CRLF{"id":"c182c1a2f71c3547ccee455563003de8","key":["Fred Smith","431","30 High street","Somehow",null],"value":null}CRLF
13:53:16.334 (2) recv: 83CRLF,CRLF{"id":"7bc7f2014593d108b5b681fe03002ad6","key":["Ian Hobson","1002","31 Sheerwater Dr","Northampton, Nhants",null],"value":null}CRLF76CRLF,CRLF{"id":"c182c1a2f71c3547ccee455563003139","key":["Julie Bloggs","302","30 Back Lane","Somewhere",null],"value":null}CRLF7cCRLF,CRLF{"id":"c182c1a2f71c3547ccee455563002e87","key": "Kingfisher Group","323","33 Westmister Rd","Londonx",null],"value":null}CRLF
13:53:16.335 (2) recv: 7aCRLF,CRLF{"id":"c182c1a2f71c3547ccee455563005894","key":["New Company","212","34 Back Street","Another Town",null],"value":null}CRLF72CRLF,CRLF{"id":"421261e8a3311c356c4900185800d7e2","key":["Three","103","3 High Street","Liverpool 8",null],"value":null}CRLF4CRLFCRLF]}CRLF1CRLFLFCRLF0CRLFCRLF
13:53:46.337 (2) recv: link closed

That is exactly as expected except that there is a 30 second delay after the database has been opened at 13:52:46.308, while the recv link times out. Not until this happens can the code open the view which happens at 13:53:16.319

However the proxy is using a different thread {(2) not (1)}. The application part works just fine without the proxy, so I suspect the proxy.

The proxy code is based on microproxy and is below

import re, sys, datetime
import socket 
import threading 
PORT = 5981
class ConnectionThread(threading.Thread): 
    def __init__(self, (conn,addr),id): 
        self.conn = conn 
        self.addr = addr
        self.id = id
        threading.Thread.__init__(self)

    def report(self,data,dir):
        txt = data.replace("\n",'LF')
        txt = txt.replace("\r",'CR')
        now = datetime.datetime.now()
        print "%s (%s) %s: %s" % (now.isoformat()[11:23],self.id,dir,txt)      

    def run(self): 
        data = self.conn.recv(1024*1024) 
        request = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        request.connect(('192.168.0.1',5984)) 
        self.report(data,'send')
        request.send(data) 
        while True: 
            temp = request.recv(1024) 
            if ('' == temp):
                self.report('link closed','recv')
                break 
            self.report(temp,'recv')
            self.conn.send(temp)
        self.conn.close()

class ProxyThread(threading.Thread): 
    def __init__(self, port): 
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        self.sock.bind(('localhost', port))
        self.count = 1
        threading.Thread.__init__(self) 
    def run(self): 
        self.sock.listen(3) 
        while True:
            temp = ConnectionThread(self.sock.accept(),self.count)
            temp.start()   # each message handled in own thread
            self.count += 1
if __name__ == "__main__": 
    print "Starting a proxy on port", PORT
    proxy = ProxyThread(PORT) 
    proxy.run() 

Both the request to open the database and the request for the view are made in the same (non GUI)
thread. Why should the delay occur?

And how can I change things so it doesn't?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绝影如岚 2024-10-25 04:48:54

您的循环仅从被代理的连接的一端读取。这样,当回复从服务器转发到客户端并且客户端断开连接时,代码不会注意到客户端断开连接,并继续等待服务器回复或断开连接。

要解决这个问题,它需要从服务器(请求)和客户端(self.conn)套接字读取。使用非阻塞套接字最容易做到这一点。

Your loop reads only from one end of the connection being proxied. So that when the reply is forwarded from the server to the client and client disconnects, the code does not notice client disconnection and keeps waiting for server reply or disconnect.

To fix that it needs to read from both server (request) and client (self.conn) sockets. It is easiest to do that by using non-blocking sockets.

め七分饶幸 2024-10-25 04:48:54

HTTP 规范 规定(第 9.4 节)

HEAD 方法与 GET 相同,只是服务器不得在响应中返回消息正文。

这意味着 CRLFCRLF 后面没有任何内容,但您的代理正在等待数据而不是从传入连接中读取数据。我怀疑 couchdb 库正在尝试使用保持活动连接,但您正在查看错误的套接字。

您的基本问题是您声称可以与 HTTP 1.1 通信,但实际上却没有。您应该注意 CRLFCRLF 序列和内容大小标头。如果发现读取了这么多数据就跳出循环,如果没有就立即break。

The HTTP spec states (section 9.4)

The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.

This means that there is nothing following the CRLFCRLF but your proxy is waiting for data rather than reading from the incoming connection. I suspect that the couchdb library is trying to use a keep-alive connection, but you're watching the wrong socket.

Your basic problem is that you claim to speak to HTTP 1.1 but you don't. You should watch for a CRLFCRLF sequence a content-size header. If you find one read that much data then break out of the loop, if there isn't one then break immediately.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文