找回密码
 立即注册

扫一扫,访问微社区

QQ登录

只需一步,快速开始

查看: 6265|回复: 3

[已解决] 为什么python多线程没有加速程序的效果,求大神解答

1

主题

3

帖子

3

积分

贫民

积分
3
bebbbeb 发表于 2016-8-22 21:24:45 | 显示全部楼层 |阅读模式
import  requests
import queue
import time
import logging
import threading

loghandel=logging.getLogger("totest")
fhand = logging.FileHandler("./log/main.log", 'a')
formator = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(module)s - %(lineno)d - %(message)s',
    '%a, %d %b %Y %H:%M:%S')
fhand.setFormatter(formator)
fhand.setLevel(logging.DEBUG)
loghandel.addHandler(fhand)
loghandel.setLevel(logging.DEBUG)


def test5(threadcount):
    reqqueue = queue.Queue()
    respqueue=queue.Queue()
    for i in range(1,624):
        reqqueue.put("http://club.autohome.com.cn/bbs/forum-c-3170-{0}.html?orderby=dateline&qaType=-1".format(i))

    def downloadpage(url):
        starttime = time.time()
        startclock = time.clock()
        rsp = requests.get(url)
        endtime = time.time()
        endclock = time.clock()
        loghandel.info(rsp.url + " " + str(rsp.elapsed.microseconds) + " " + str(rsp.status_code) + " " + str(
            endtime - starttime)+" "+ str(endclock - startclock))
        respqueue.put(rsp)
    while reqqueue.qsize()!=0:
        threadpool=[]
        for i in range(1, threadcount):
            try:
                page = reqqueue.get(block=False)
                t = threading.Thread(target=downloadpage(page))
                threadpool.append(t)
            except queue.Empty as e:
                loghandel.error("the pagequeue is empty")
                break
        for t in threadpool:
            t.start()

        for t in threadpool:
            t.join()

        threadpool.clear()
    return respqueue

if __name__ == '__main__':
    for i in [2, 6, 11, 31, 51]:
        starttime = time.time()
        startclock = time.clock()
        test5(i)
        endtime = time.time()
        endclock = time.clock()
        print(str(i - 1), endtime - starttime, endclock - startclock)

---------------------------------------------------------------------------------------------------------------------------------------
1.这一个简单的抓取网页信息的脚本,六百多页要三分钟,于是就该多线程了,测了一下,感觉没有效果啊
1 244.80229902267456 7.2211739999999995
5 242.83057475090027 6.998869
10 244.70902132987976 6.464195000000002
30 242.68053889274597 6.5377849999999995
50 231.3118827342987 6.582313999999997
三列分别代表了 线程数 time.time()的差值和time.clock()的差值。时间的变化感觉可以忽略不计了。
2.观察了一下日志,截取一段日志内容如下:
Mon, 22 Aug 2016 20:22:04 - totest - INFO - totest - 85 - http://club.autohome.com.cn/bbs/ ... =dateline&qaType=-1 520455 200 0.5733683109283447 0.009866000000002373
Mon, 22 Aug 2016 20:22:04 - totest - INFO - totest - 85 - http://club.autohome.com.cn/bbs/ ... =dateline&qaType=-1 551292 200 0.6094365119934082 0.010680999999998164
Mon, 22 Aug 2016 20:22:05 - totest - INFO - totest - 85 - http://club.autohome.com.cn/bbs/ ... =dateline&qaType=-1 528814 200 0.5740671157836914 0.012908000000003028
Mon, 22 Aug 2016 20:22:06 - totest - INFO - totest - 85 - http://club.autohome.com.cn/bbs/ ... =dateline&qaType=-1 558045 200 0.6106369495391846 0.008852000000004523
Mon, 22 Aug 2016 20:22:06 - totest - INFO - totest - 85 - http://club.autohome.com.cn/bbs/ ... =dateline&qaType=-1 499849 200 0.5567328929901123 0.010531999999997765
Mon, 22 Aug 2016 20:22:07 - totest - INFO - totest - 85 - http://club.autohome.com.cn/bbs/ ... =dateline&qaType=-1 523191 200 0.5853497982025146 0.00894800000000373
既然是并发的,那么页号从616到621怎么是顺序的呢?不应当是哪一个请求先结束就行记录哪一个请求吗?
请大家指教

回复

使用道具 举报

0

主题

1

帖子

1

积分

贫民

积分
1
skyoiiowalker 发表于 2016-8-23 13:19:33 | 显示全部楼层
本帖最后由 skyoiiowalker 于 2016-8-23 13:24 编辑

t = threading.Thread(target=downloadpage(page)) 这句话有误,你这实际上是主线程调用downloadpage(page),然后把返回值赋值给target,你可以在downloadpage方法种加入print threading.current_thread().getName()语句看看执行的线程就知道了,应该写成:
t = threading.Thread(target=downloadpage,args=(page,))

因此你代码执行的效果就是main线程串行执行,没有其他线程并发。
其次,你这个线程池是不对的,你这样写每次都会创建一个新的线程对象去执行downloadpage方法,达不到线程复用的目的..
回复 支持 1 反对 0

使用道具 举报

50

主题

1057

帖子

1108

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
1108

活跃会员热心会员最佳导师默默耕耘突出贡献优秀版主荣誉管理论坛元老

blueelwang 发表于 2016-8-23 17:50:13 | 显示全部楼层
skyoiiowalker 发表于 2016-8-23 13:19
t = threading.Thread(target=downloadpage(page)) 这句话有误,你这实际上是主线程调用downloadpage(page) ...

分析的很透彻
回复 支持 反对

使用道具 举报

1

主题

3

帖子

3

积分

贫民

积分
3
bebbbeb  楼主| 发表于 2016-8-25 08:23:55 | 显示全部楼层
skyoiiowalker 发表于 2016-8-23 13:19
t = threading.Thread(target=downloadpage(page)) 这句话有误,你这实际上是主线程调用downloadpage(page) ...

感谢指点。我又改进了一下,downloadpage这个方法不传参数了,在这个方法里面加了一个循环,如果队列中仍有url,就取出来并访问。这样就不用每次创建对象了。抓取速度简直飞一般的感觉。不过这个也就是取个巧,还不是线程池。我百度过,python3好像是没有现成的线程池方面的包的,不知道是不是这样。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表