多线程与多线程爬虫

多任务的概念

什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边看电影,一边聊QQ,一边在用Word赶作业,这就是多任务,这时至少同时有3个任务正在运行。
单核CPU如何执行多任务? 多核CPU如何执行多任务?
真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。


并发:在一个核心中多个人物交替执行,任务是同时发起,但并不是同时执行
并行:任务数量小于或等于核心数量,这个时候每个核心都在执行任务任务是同时执行的

threading.Thread参数介绍:
  1. target:线程执行的函数
  2. name:线程名称
  3. args:执行函数中需要传递的参数,元组类型 另外:注意daemon参数
    如果某个子线程的daemon属性为False,主线程结束时会检测该子线程是否结束,如果该子线程还在运行,则主线程会等待它完成后再退出;

如果某个子线程的daemon属性为True,主线程运行结束时不对这个子线程进行检查而直接退出,同时所有daemon值为True的子线程将随主线程一起结束,而不论是否运行完成。

属性daemon的值默认为False,如果需要修改,必须在调用start()方法启动线程之前进行设置

互斥锁

当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
互斥锁为资源引入一个状态:锁定/非锁定
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。


锁的好处:确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:1.阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
2.由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁


多线程爬虫

Queue(队列对象)

Queue是python中的标准库,可以直接import Queue引用;
队列是线程间最常用的交换数据的形式

python下多线程的思考

对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue,是线程安全的,因此在满足使用条件下,建议使用队列
1.初始化: class (FIFO 先进先出)

Queue.Queue(maxsize)  
maxsize(队列的长度)

2.包中的常用方法:

Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间

3.创建一个“队列”对象

import Queue
myqueue = Queue.Queue(maxsize = 10)

4.将一个值放入队列中

myqueue.put(10)

5.将一个值从队列中取出

myqueue.get()
QQ截图20181202225351.png

实例演示

import requests
import threading
from lxml import etree
import queue

class crawlThread(threading.Thread):
def __init__(self,threadName,page_queue,data_queue):
super(crawlThread,self).__init__()
self.threadName = threadName
self.page_queue = page_queue
self.data_queue = data_queue
self.headers = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0',}

def run(self):
# 这里从page_queue获取对应的页码
while not self.page_queue.empty():
#get()从队列中取值,先进先出
page = self.page_queue.get()
print(page)
full_url = 'http://blog.jobbole.com/all-posts/page/'+str(page)+'/'
response = requests.get(full_url,headers=self.headers)
response.encoding = 'utf-8'
if response.status_code == 200:
#将获取到的结果,存放在data_queue队列中
self.data_queue.put(response.text)
# #线程的采集任务
# def crawl_data(page_queue,data_queue):
# header = {
# 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0',
# }
# # 这里从page_queue获取对应的页码
# while not page_queue.empty():
# #get()从队列中取值,先进先出
# page = page_queue.get()
# print(page)
# full_url = 'http://blog.jobbole.com/all-posts/page/'+str(page)+'/'
# response = requests.get(full_url,headers=header)
# response.encoding = 'utf-8'
# if response.status_code == 200:
# #将获取到的结果,存放在data_queue队列中
# data_queue.put(response.text)

# def parse_data(data_queue):
# #不为空的时候去取值,为空说明没有解析任务了
# while not data_queue.empty():
# html = etree.HTML(data_queue.get())
# articles = html.xpath('//div[@class="post floated-thumb"]')
# for item in articles:
# title = item.xpath('.//a[@class="archive-title"]/text()')[0]
# print(title)

class parseThread(threading.Thread):
def __init__(self,threadName,data_queue,lock):
super(parseThread,self).__init__()
self.threadName = threadName
self.data_queue = data_queue
self.lock = lock

def run(self):
#不为空的时候去取值,为空说明没有解析任务了
while not self.data_queue.empty():
html = etree.HTML(self.data_queue.get())
articles = html.xpath('//div[@class="post floated-thumb"]')
for item in articles:
title = item.xpath('.//a[@class="archive-title"]/text()')[0]
print(title)
#加锁
self.lock.acquire()
with open('jobbole.txt','a') as f:
f.write(title+'\n')
#解锁
self.lock.release()

def spider():
#创建一个任务队列:里面的参数maxsize表示最大的存储量
page_queue = queue.Queue(40)
#http://blog.jobbole.com/all-posts/page/2/ (2表示页码)
for i in range(1,30):
page_queue.put(i)

#将解析后的数据放在这个队列中,供后后面的解析线程去做解析
data_queue = queue.Queue()

#创建线程取下载任务
lock = threading.Lock()
crawlThreadName = ['crawl1号','crawl2号','crawl3号','crawl4号']
thread_list = []
for threadName in crawlThreadName:
# thread = threading.Thread(target=crawl_data,name=threadName,args=(page_queue,data_queue))
thread = crawlThread(threadName,page_queue,data_queue)
thread.start()
thread_list.append(thread)
# thread.join() 不能直接写在这里

for thread in thread_list:
thread.join()

#创建解析线程:
parseThreadName = ['parse1号','parse2号','parse3号','parse4号']
parseThread_list = []
for threadName in parseThreadName:
# thread = threading.Thread(target=parse_data,name=threadName,args=(data_queue,))
thread = parseThread(threadName,data_queue,lock)
thread.start()
parseThread_list.append(thread)
for thread in parseThread_list:
thread.join()
#打印当前线程的名称
print(threading.current_thread().name)

if __name__ == '__main__':
spider()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 11,232评论 4 56
  • iOS多线程编程 基本知识 1. 进程(process) 进程是指在系统中正在运行的一个应用程序,就是一段程序的执...
    陵无山阅读 5,996评论 1 14
  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,294评论 8 265
  • 先抛开区块链,只讲P2P,对P2P了解后,再慢慢解开区块链对P2P的应用。 P2P发展历史 本文是从《P2P对等网...
    jection阅读 878评论 0 0
  • 在下午和沙发一起呼吸夏日的慵懒圆桌、咯哑的柜子未碰面就已疏离阳光在墙上穿行冲破一场漫不经心的对话像苍蝇在烟雾中困倦...
    公子非阅读 433评论 27 33