python是单线程还是多线程_对比python的I/O密集型单线程和多线程

上次对比了计算密集型,单线程居然会优于多线程,原因如下(摘自百度,哈哈哈):

Python是解释型语言,那么它在运行的时候就需要解释器了,简单描述下GIL,即global interpreter lock,全局解释器锁,就是python在运行的时候会锁定解释器,就是说在运行的时候只能是一个线程,锁死了,切换不了;每个线程在运行之前都要申请GIL,那么就必须要等上一个线程释放这把锁你才可以申请到,然后执行代码,执行完后,你再交给下一个线程,让它去执行代码,过程如下:

设置GIL -> 切换到一个线程去执行 -> 运行 -> 把线程设置为睡眠状态 -> 解锁GIL

这次对比下I/O密集型,理论上多线程肯定优于单线程,理论是不是对的呢?

对比方法,类似爬虫案例,处理30个url,单线程去挨个访问耗费时长和多线程去访问耗费时长进行比较。这里用一个基金网站为例,程序前面两个函数处理该基金网站,主要是为了获取多个url。然后单线程就直接调用函数get_url访问30个url并纪录耗时,最后用多线程对比记录耗时。结果,理论仍然是正确的哈!

# -*- encoding=UTF-8 -*-

__author__ = 'wjj1982'

__date__ = '2019/8/19 20:46'

__product__ = 'PyCharm'

__filename__ = '多线程爬某基金网'

from bs4 import BeautifulSoup as bs

import requests

import re

import time

from queue import Queue

from threading import Thread

# 输入一个url,然后get页面信息,最后返回页面content和页面code

def get_url(url):

if url is None:

return None

try:

response = requests.get(url)

except Exception as e:

print('get url failed,error is:{}'.format(e))

return None

if response.status_code != 200:

return None

return response.status_code, response.content

def handle_response(content):

bs_content = bs(content, 'html.parser', from_encoding='gb18030')

urls_fund = bs_content.find_all('ul', class_='num_right')

fund_list = []

for url_fund in urls_fund:

for each_li in url_fund.find_all('li'):

fund_info_dict = {'fund_id': '',

'fund_name': '',

'fund_url': ''}

each_a = each_li.find_all('a')

if len(each_a) > 0:

each_a = each_a[0]

fund_info_dict['fund_id'] = re.findall(r'\d+', each_a.text)[0]

fund_info_dict['fund_name'] = each_a.text.split(')')[1]

fund_info_dict['fund_url'] = each_a['href']

# fund_info_dict['fund_url'] = each_a.attrs['href']

fund_list.append(fund_info_dict)

return fund_list

# 自定义一个线程继承于threanding.Thread,用来多线程处理获取页面用,传入的时queue队列,queue队列里面放的就是多个url

# 多进程就是分别从队列里取url并行处理,最后返回code做汇总统计

class my_thread_get_url(Thread):

# 类初始化,注意这里super要init一下,否则报thread没有初始化

def __init__(self, queue):

super(my_thread_get_url, self).__init__()

self.queue = queue

def run(self):

while True:

if self.queue.empty():

break

else:

fund_url = self.queue.get()

code_response1, content_response1 = get_url(fund_url)

print(code_response1)

if __name__ == '__main__':

# 这一部分是获取所有基金的url

url = 'http://fund**************'

code_response, content_response = get_url(url)

fund_list = handle_response(content_response)

# 单线程处理30个url

print('单线程开始处理30个url')

start = time.time()

for fund in fund_list[:29]:

code_response, content_response = get_url(fund['fund_url'])

print(code_response)

end = time.time()

print('单线程处理30个url时的耗时:{}'.format(end - start))

# 多线程处理30个url

print('多线程处理30个url')

start1 = time.time()

my_queue = Queue()

my_thread_list = []

# url入列,put入列,get为出列,empty查询为空时break

for fun in fund_list[:29]:

my_queue.put(fun['fund_url'])

# 三个线程并发执行,电脑能力强的话可以更多线程执行哈,我觉得主要和CPU能力还有内存大小相关

for i in range(3):

my_thread_class = my_thread_get_url(my_queue)

my_thread_list.append(my_thread_class)

my_thread_class.start()

# 阻塞,线程阻塞等待子线程执行完,主线程结束

for t in my_thread_list:

t.join()

end1 = time.time()

print('多线程处理30个url时的耗时:{}'.format(end1 - start1))

多线程处理IO密集型对比结果.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值