我在PyQt4中编写了一个程序,使用post请求上传文件到XFS。一切都很好,但速度极低。
使用另一个程序,我获得了70 Mb / s的吞吐量但是我写的东西我最多只能达到8 Mb / s。低速的原因是什么?
我怀疑我需要使用不同的连接。我搜索并发现Qt上的回复,建议这个QFtp,我不知道它是否适用于http。
编辑:为清除问题添加演示,它几乎涵盖了我上传的所有内容(我没有测试示例代码,但它应该可以正常工作)
edit2 :使用此代码我上传8 Mb / s,而在确切情况下另一个程序给出70 Mb / s,速度有很大差异
我在代码中解释了重要的事情
from PyQt4 import QtCore, QtGui, QtNetwork
import requests
import time
class Window(QtGui.QWidget):
def __init__(self, address):
QtGui.QWidget.__init__(self)
self.address = address
self.table = QtGui.QTableWidget(self)
header = self.table.horizontalHeader()
header.setStretchLastSection(True)
header.hide()
self.table.setColumnCount(2)
self.button = QtGui.QPushButton('Add Upload', self)
self.button.clicked.connect(self.handleAddUpload)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.table)
layout.addWidget(self.button)
self.netaccess = QtNetwork.QNetworkAccessManager(self)
self._uploaders = {}
def handleAddUpload(self):
#in main program this is a loop actually,to handle batch upload
#for....
stream = QtCore.QFile('icon.png')
if stream.open(QtCore.QIODevice.ReadOnly):
self.ts = time.time() #we will use this later
data = stream
row = self.table.rowCount()
button = QtGui.QPushButton('Abort', self.table)
button.clicked.connect(lambda: self.handleAbort(row))
progress = QtGui.QProgressBar(self.table)
progress.setRange(1, stream.size())
self.table.setRowCount(row + 1)
self.table.setCellWidget(row, 0, button)
self.table.setCellWidget(row, 1, progress)
uploader = self._uploaders[row] = Uploader(row, self.netaccess)
uploader.uploadProgress.connect(self.handleUploadProgress)
uploader.uploadFinished.connect(self.handleUploadFinished)
uploader.upload(data, self.address)
def handleUploadProgress(self, key, sent, total):
print'upload(%d): %d [%d]' % (key, sent, total)
#I test it,when I call this three method,upload speed in my local become 3 mb
#but when I Comment these methods speed is over 70 mb
#problem is here I guess
self.humansize(sent, total)
self.humantransferrate(sent)
self.timeleft(sent, total)
#I commented next lines because here we don't have a table but in main
#program these are not commented and change table cells rapidly
#self.sentsizelabel = QtGui.QLabel(str(self.humansent))
#self.totalsizelabel = QtGui.QLabel(str(self.humantotal))
#self.transferlabel = QtGui.QLabel(str(self.tr))
#self.timeleftlabel = QtGui.QLabel(str("{0}").format(self.timeLeft))
#self.table.setCellWidget(key, 1, self.sentsizelabel)
#self.table.setCellWidget(key, 2, self.totalsizelabel)
#self.table.setCellWidget(key, 5, self.transferlabel)
#self.table.setCellWidget(key, 3, self.timeleftlabel)
progress = self.table.cellWidget(key, 1)
progress.setValue(sent)
def handleUploadFinished(self, key):
print'upload(%d) finished' % key
button = self.table.cellWidget(key, 0)
button.setDisabled(True)
uploader = self._uploaders.pop(key)
uploader.deleteLater()
def handleAbort(self, key):
try:
self._uploaders[key].abort()
except (KeyError, AttributeError):
pass
def humantransferrate(self,sent): #sorry if it's not clean
now = time.time() #get time()
uploadTime = now - self.ts #self.ts is the time() when uploaded started,uploadTime is time between start upload and now
self.trfirst = (sent/1024)/uploadTime# turning byte to Kb
if self.trfirst > 1000:#retun better format of transfer rate
self.trlast = self.trfirst/1024
self.tr = str('{0:.1f} Mb'.format(self.trlast))
else:
self.tr = str('{0:.2f} Kb'.format(self.trfirst))
return
def timeleft(self, sent, total):
leftSize = total-sent
now = time.time() #right now
uploadTime = now - self.ts #self.ts is the time() when upload started
#compute time left
#here we use Proportion to figure out time left
param = leftSize * uploadTime
try:
timeLen = param/sent
except: #this is because for very very small files param/sent will return 0
timeLen = 0.001
if timeLen > 60:#return best format
self.timeLeft = '{0:.1f} min'.format(timeLen / 60)
else:
self.timeLeft = '{0:.0f} sec'.format(timeLen)
def humansize(self, sent, total):
if sent/1000 > 1000: #return right format
self.humansent = '{0:.1f} Mb'.format(sent/1000000)
else:
self.humansent = '{0:.2f} Kb'.format(sent/1000)
if total/1000 > 1000: #return right format
self.humantotal = '{0:.1f} Mb'.format(total/1000000)
else:
self.humantotal = '{0:.2f} Kb'.format(total/1000)
return self
class Uploader(QtCore.QObject):
uploadProgress = QtCore.pyqtSignal(object, int, int)
uploadFinished = QtCore.pyqtSignal(object)
def __init__(self, key, parent):
QtCore.QObject.__init__(self, parent)
self._key = key
self._reply = None
def abort(self):
if self._reply is not None:
self._reply.abort()
def upload(self, data, url):
if self._reply is None:
#in here I read from a json file to get cookies,this is fast I guess
#with open.....
self._stream = data
self._multiPart = QtNetwork.QHttpMultiPart(QtNetwork.QHttpMultiPart.FormDataType)
fileName = QtCore.QFileInfo(self._stream.fileName()).fileName()
key = 'file'
imagePart = QtNetwork.QHttpPart()
imagePart.setHeader(QtNetwork.QNetworkRequest.ContentDispositionHeader,
"form-data; name=\"%s\"; filename=\"%s\"" % (key, fileName))
imagePart.setBodyDevice(self._stream)
self._multiPart.append(imagePart)
#sending login data
#self._multiPart.append(sessPart)
#self._multiPart.append(submitPart)
request = QtNetwork.QNetworkRequest(QtCore.QUrl(url))
request.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader,
'multipart/form-data; boundary=%s' % self._multiPart.boundary())
request.setRawHeader('User-Agent','Mozilla/5.0')
request.setRawHeader('Cookie', 'some cookie from json file')
self._reply = self.parent().post(request, self._multiPart)
self._reply.uploadProgress.connect(self.handleUploadProgress)
self._reply.finished.connect(self.handleFinished)
def handleUploadProgress(self, sent, total):
#when I comment this and print transfer rate in here speed is over 70 mb
self.uploadProgress.emit(self._key, sent, total)
def handleFinished(self):
#here I use requests again to get uploaded url from an html page(parsing it) I didn't write it because I it's better to code be shorter
self._stream.close()
self._multiPart.deleteLater()
self._reply.deleteLater()
self._reply = None
self.uploadFinished.emit(self._key)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window('http://localhost/upload.php')
window.setGeometry(500, 300, 500, 300)
window.show()
sys.exit(app.exec_())
我不确定,但我想如果我在Uploader.handleUploadProgress()中发出uploadProgress,每5秒钟就会解决一个问题: - ?但如果有效的话,不知道如何测试
编辑:现在问题解决了,我在Window.UploadProgress中使用并尝试使用if来使其正常工作,但这根本不是好办法,如果你们有任何建议我我很想知道
答案 0 :(得分:0)
也许您正在使用Python的文件api读取文件,然后通过QByteArray
传递字节?
确保您将QFile
的实例作为post
方法的第二个参数传递。
但首先,发布一个重现问题的最小例子。它可能只有十几行 - 记住,它毕竟是Python。它应该大致如下:
file = QFile("file.zip")
if not file.open(QIODevice.ReadOnly):
return
request = QNetworkRequest("http://foo.bar.baz/upload")
reply = networkAccessManager.post(request, file)
如果您正在使用多部分请求,它应该与下面的代码大致相同。感谢setParent
提示Andrew Suffield。
filename = "file.zip"
file = QFile(filename)
if not file.open(QIODevice.ReadOnly):
return
multipart = QHttpMultiPart(QtNetwork.QHttpMultiPart.FormDataType)
filepart = QHttpPart()
filepart.setHeader(QNetworkRequest.ContentTypeHeader, 'application/octet-stream')
filepart.setHeader(QNetworkRequest.ContentDispositionHeader, 'form-data; name="%s"; filename="%s"' % ('file', filename))
filepart.setBodyDevice(file)
multipart.append(filepart)
reply = manager.post(request, multipart)
# Hook multipart to the reply so that it sticks around for the lifetime of the request
multipart.setParent(reply)
这些应该不会比同等的C ++代码更差,所以如果有问题,只要你的其他代码是理智的,它可能在Qt中正确。