一次失败的QThread多线程加载Webpage.load()页面的尝试
2016-07-19 15:09
806 查看
问题
前段时间在用PyQt4写网页加载部分时一开始用的从QWebView.load()(QWebFrame.load()),但由于这样会卡住GUI,于是换了QNetworkAccessManager模块来访问网络,返回内容用setcontent()传递给QWebView:http://blog.csdn.net/chroming/article/details/51832244
当时还觉得解决了一个挺有意义的问题,毕竟搜索GUI卡住的问题确实有不少人因为load()导致GUI界面卡住。
由于QNetworkAccessManager是比较底层的访问网络模块,不少东西要自己处理。比如某些网址HTML中声明的编码与response header中声明的编码不同导致的网页显示乱码,某些网页无法显示等问题。对于乱码问题我还通过读取response header解决了一部分,但对于无法显示的问题却没找到原因。后来测试QWebFrame.load(),发现这些问题都不存在。于是考虑使用多线程加载网页,既能解决各种兼容性问题,又不会导致GUI卡住。
寻找解决办法
虽然Python自己有多线程模块,但因为程序里用了很多Qt模块,这里也考虑直接用Qt的自带多线程模块,QThread。搜了资料,写出了独立的多线程模块:# -*- coding: utf-8 -*- from PyQt4 import QtCore # load加载页面线程 class loadUrl(QtCore.QThread): def __init__(self, qurl, qwebframe, parent=None): super(loadUrl, self).__init__(parent) self.qurl = qurl self.qwebframe = qwebframe def run(self): self.qwebframe.load(self.qurl)
在主代码中调用多线程模块:
class test(): ... def testfun(): ... from multiThread import loadUrl self.multiget = loadUrl(QUrl(input_url), self.webView.page().mainFrame()) self.multiget.start()
结果出现了错误:
QObject: Cannot create children for a parent that is in a different thread
网上查到类似的情况:http://stackoverflow.com/questions/7143088/how-do-you-set-up-multiple-multithreaded-qwebviews-in-pyqt
回答如下:
There are multiple issues with your question and code:
You are talking about QWebFrame, but are actually passing a QWebView to your worker(s). Since this is a QWidget, it belongs to the main (GUI) thread and should not be modified by other threads.
One QWebView / QWebFrame can only load one URL at a time, so you cannot share it across multiple workers.
QWebFrame.load() loads data asynchronously, i.e. a call to load() returns immediately and there will be no data to read yet. You will have to wait for the loadFinished() signal to be emitted before you can access the data.
Since the actual loading is done by the networking layer of the operating system, and the *load()*method does not block, there is no need to run it in a separate thread in the first place. Why do you claim that this should be faster – it makes no sense.
Since you want to load hundreds of URLs in parallel (or about 10, you are mentioning both in the same sentence), are you sure that you want to use QWebFrame, which is a presentation class? Do you actually want to render the HTML or are you just interested in the data retrieved?
其中第一个issue回答了为什么会出现这个报错:主线程中的QWebFrame不能用子线程修改。但相比这条我更在意第三第四条:QWebFrame.load()是异步加载页面的,并不会阻塞主线程,不需要用子线程去加载页面。这就奇怪了,之前我用的时候明明是因为加载页面导致GUI卡住的。于是回去看自己的代码,发现了一点:
self.webView.load(QUrl(input_url)) app.restoreOverrideCursor()
于是随手把
app.restoreOverrideCursor()改到load之前。结果发现不卡了!一直以来困扰我的竟然是由于这个!
总结
这个问题让我花了一些冤枉时间来处理网页兼容性,结果发现只是一个小小的失误导致的。虽然之前在搜索网页卡住的问题时也看到有人说load()是异步加载,但由于自己的程序确实卡住了这个事实,也没深究为什么异步还会卡住。今后在处理问题时需要更加仔细。参考资料:
《PyQt 分离UI主线程与工作线程》http://blog.csdn.net/Mr_Zing/article/details/46945011
《How do you set up multiple multithreaded QWebViews in PyQt?》http://stackoverflow.com/questions/7143088/how-do-you-set-up-multiple-multithreaded-qwebviews-in-pyqt
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- C#实现多线程的同步方法实例分析
- 浅谈chuck-lua中的多线程
- C#简单多线程同步和优先权用法实例
- C#多线程学习之(四)使用线程池进行多线程的自动管理
- C#多线程编程中的锁系统(三)
- 解析C#多线程编程中异步多线程的实现及线程池的使用
- C#多线程学习之(六)互斥对象用法实例
- 基于一个应用程序多线程误用的分析详解
- C#多线程学习之(三)生产者和消费者用法分析
- C#多线程学习之(一)多线程的相关概念分析
- C#多线程之Thread中Thread.IsAlive属性用法分析
- 分享我在工作中遇到的多线程下导致RCW无法释放的问题
- C#多线程编程之使用ReaderWriterLock类实现多用户读与单用户写同步的方法
- C#多线程传递参数及任务用法示例
- C#控制台下测试多线程的方法
- 21天学习android开发教程之SurfaceView与多线程的混搭
- Ruby 多线程的潜力和弱点分析
- C#中WPF使用多线程调用窗体组件的方法
- C#如何对多线程、多任务管理(demo)