Python 刚学, 纠结于多线程 concurrent.futures 的错乱的问题,请教下各位? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
GreenJoson
V2EX    Python

Python 刚学, 纠结于多线程 concurrent.futures 的错乱的问题,请教下各位?

  •  
  •   GreenJoson 2019-12-16 18:18:15 +08:00 4257 次点击
    这是一个创建于 2135 天前的主题,其中的信息可能已经有所发展或是发生改变。

    按照手册实例结合自己想写的一个多访问的脚本,有了以下的代码.有 2 种写法的: 第 1 种速度快很多,但是出现多个 print 输出,实在想不出怎么冒出来的.是线程出错还是线程多余的.我开的 5 个线程,print(future_to_url) 对象也是 5 个.但是跑起来就多了出 3 个,而且文字还错乱了.

    第 2 种暂时没有发现问题,求指教第一种为何会出现这种问题?

    URLS = {'baidu':'http://www.baidu.com', 'sogou':'http://www.sogou.com', 'so':'http://www.so.com', 'youku':'http://www.youku.com', 'qq':'http://www.qq.com' } def load_url(s,args): weburl = args['url'] if args['mark'] == 'baidu': print(s + "百度访问:" + weburl) rs = requests.get(weburl) if args['mark'] == 'so': print(s + "so:" + weburl) rs = requests.get(weburl) if args['mark'] == 'sogou': print(s + "搜狗访问:" + weburl) rs = requests.get(weburl) if args['mark'] == 'qq': print(s + "腾讯访问:" + weburl) rs = requests.get(weburl) if args['mark'] == 'youku': print(s + "优酷访问:" + weburl) rs = requests.get(weburl) return str(rs.status_code) title = '速度与激情' cOnData={'year':'2015','actor':'范迪塞尔,保罗沃克,杰森斯坦森,米歇尔罗德里格兹','subname':'狂野时速 7'} aa = [] start = datetime.datetime.now() with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: # --------------------------------第 1 种.写法----------------------------------------------# future_to_url = {executor.submit(load_url,title,conData): (conData['mark'] ,conData['url']) for conData['mark'],conData['url'] in URLS.items()} print(future_to_url) for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] #调用对应的 URL try: data = future.result() #获得函数返回的值 except Exception as exc: print('%r generated an exception: %s' % (conData['url'], exc))#调试异常错误 else: aa.append(data) #--------------------------------第 2 种.写法----------------------------------------------# # for conData['mark'],conData['url'] in URLS.items(): # future = executor.submit(load_url, title, conData) # print(future) # try: # data = future.result() #获得函数返回的值 # except Exception as exc: # print('%r generated an exception: %s' % (conData['url'], exc))#调试异常错误 # else: # aa.append(data) executor.shutdown(wait=True) end = datetime.datetime.now() print (end-start) 

    Snipaste_2019-12-16_17-42-54.jpg

    11 条回复    2019-12-16 21:03:09 +08:00
    superrichman
        1
    superrichman  
       2019-12-16 19:55:08 +08:00   1
    GreenJoson
        2
    GreenJoson  
    OP
       2019-12-16 20:16:59 +08:00
    @superrichman 谢谢大佬,但是这个结果可能不是我想要的.
    URLS = {'baidu': ('http://www.baidu.com', '百度'), 这块 key 是为了识别,然后对应不同的网页规则,取不同的内容.
    我只是示例一下.这个.
    title = '速度与激情'
    cOnData= {'year': '2015', 'actor': '范迪塞尔,保罗沃克,杰森斯坦森,米歇尔罗德里格兹', 'subname': '狂野时速 7'}
    我之所以多了这一个,是因为这个字典变量是固定的,我需要加入这块字典去与获取的网址内容做对比.

    def load_url(s,args):
    weburl = args['url']
    if args['mark'] == 'baidu':
    print(s + "百度访问:" + weburl)
    rs = requests.get(weburl)
    if args['mark'] == 'so':
    print(s + "so:" + weburl)
    rs = requests.get(weburl)
    if args['mark'] == 'sogou':
    print(s + "搜狗访问:" + weburl)
    rs = requests.get(weburl)
    if args['mark'] == 'qq':
    print(s + "腾讯访问:" + weburl)
    rs = requests.get(weburl)
    if args['mark'] == 'youku':
    print(s + "优酷访问:" + weburl)
    rs = requests.get(weburl)
    return str(rs.status_code)

    这块主要是想判断不同的 mark 然后 get 不同的网站取相关内容.

    可否告知我那个问题滥用的地方在哪里,谢谢~
    ipwx
        3
    ipwx  
       2019-12-16 20:18:40 +08:00   1
    “for conData['mark'],conData['url'] in URLS.items():”

    你不觉得这种用法很别扭么。。
    ----

    首先,文字错乱是正常的。因为多线程,print 是同时执行的。你要保证 print 不错乱,得加锁,或者干脆收集到同一个线程里面去 print。

    其次,我告诉你为啥会多出三项。就是因为你这个蹩脚的 for conData['mark'], conData['url']。说实话我很惊讶,因为我用 Python 这么多年,我都知不道 Python 能这么写。。。 从语义上看,这个写法的含义是把 URLS.items() 里面 for 出来的东西直接赋值到 conData 的这两个 entry 上面。

    但是啊,少年,conData 只有一个哟,但你的线程有五个诶~ 所以你某个线程在执行某一个 if args['mark'] == 'xxx': 里面的 requests.get ,执行完以后,突然在下一个 if args['mark'] == 'yyy': 的时候,args['mark'] 就已经变化了,它发现又匹配了,就又执行了一遍。
    GreenJoson
        4
    GreenJoson  
    OP
       2019-12-16 20:18:53 +08:00
    @superrichman 然后做一些友善的提示,比如访问到哪个站点了...是否在线程里面不可以用 if 来判断?不然为何到最后多显示 3 条 print
    ipwx
        5
    ipwx  
       2019-12-16 20:20:27 +08:00
    最后评论一下:我不明白你为什么会有搞一个全局对象做 for 循环调用函数传参对象的这么一个需求,不应该创建一个局部的临时变量做参数么。。。这才是你的 bug 根源,也是我这么多年没写过这种神奇代码的理由。
    GreenJoson
        6
    GreenJoson  
    OP
       2019-12-16 20:21:04 +08:00
    @ipwx 一语点破..谢谢你..“for conData['mark'],conData['url'] in URLS.items():” ,conData 只是为了加入一个字典里面,然后传递给函数,让函数去跟另一个字典做交集处理..哈哈..只是想偷懒而己.~
    谢谢你,我知道问题所在了.~
    ipwx
        7
    ipwx  
       2019-12-16 20:22:27 +0800
    @GreenJoson 这种偷懒写法,随便重构一下就是一堆 bug 的根源。。。
    ClericPy
        8
    ClericPy  
       2019-12-16 20:27:32 +08:00
    for conData['mark'], conData['url'] in URLS.items() 这倒霉用法把我吓一跳...

    建议多看看软件设计的原则那些东西, 不求全懂, 得会点常识, 至少把单一职责和高内聚低耦合做好.

    祝早日写出让人读的赏心悦目的代码...
    GreenJoson
        9
    GreenJoson  
    OP
       2019-12-16 20:34:17 +08:00
    @ClericPy @ipwx 谢谢大佬的虚拟教诲~ 有没有相关的书籍可以推荐或者视频,可以学习一下~
    ClericPy
        10
    ClericPy  
       2019-12-16 20:39:41 +08:00
    @GreenJoson #9

    我可不是大佬, 最近也在从头看设计模式, 自己写了太多屎山, 不过现在搜到的博客讲的都各说各有理...

    大部分设计原则还是学设计模式时候里面捎带的, 我以前看的酷壳写的那个 https://coolshell.cn/articles/4535.html 不过比较旧. 要么就是随手翻的四人帮那个设计模式

    虽说大部分人不看设计模式随着经验也能自发产生免疫力, 但是有这种捷径类疫苗在, 可以比较快地让自己知道自己哪里不优雅, 最后忠告就是别迷信设计模式
    GreenJoson
        11
    GreenJoson  
    OP
       2019-12-16 21:03:09 +08:00
    @ClericPy 谢谢你的忠告,我先看看你发的.感谢~
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5769 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 03:06 PVG 11:06 LAX 20:06 JFK 23:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86