爬虫-多线程和线程池
一、多线程
1、了解多线程之前,先了解一下单线程程,顾名思义就是一条流水线;看下面代码
def func(): for i in range(100): print('func',i) if __name__ =='__main__': func() for i in range(100): print('main',i)
运行后【省略部分】:
func 0 func 1 func 2 func 3 func 4 func 5 func 6 func 7
....
运行的过程:
- 1、首先创建出func函数
- 2、由程序入口进入 -----
- 3、开始调用func()方法-------
- 4、结束后继续往下执行
- 5、执行打印main
2、多线程就是多条流水线同时在工作,如何定义一个多线程?
- 需要先声明:
from threading import Thread #线进程
- 多线程是如何定义的,看下面代码
def func(): for i in range(100): print("func" , i) if __name__ == '__main__': t = Thread(target=func) # 创建线程并给线程安排任务 t.start() #多线程状态为可以开始工作状态, 具体的执行时间由CPU决定 for i in range(100): print("main",i)
- 运行结果,比较杂乱,两个线程同时在运行
main 1 func 21 func main 2 main 3 func3 ....
3、定义多线程的另一种方式:定义mytread类去继承父类Thread
class MyThread(Thread): def run(self): for i in range(100): print('子线程1',i) class myThread2(Thread): def run2(self): for i in range(100): print('子线程2',i) if __name__ =='__main__': t = MyThread() t.start() t2 = myThread2() t2.start() for i in range(100): print("主线程" ,i)
4、以上的线程都是无参的,如何定义有参线程
from threading import Thread def func(name): for i in range(100): print(name,i) if __name__ == '__main__': t1 = Thread(target = func,args=("周星驰",)) t2 = Thread(target = func,args=("王二小",)) #元组 t1.start() #开启进程 t2.start() )
二、线程池
1、什么是线程池,线程池就是一个池子,当需要多线程的时候,就会到线程池中去取,
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor #导包
def fuc(name): for i in range(10): print(name,i) if __name__ == "__main__": with ThreadPoolExecutor(10)as t : t.submit(fuc,"周杰伦") t.submit(fuc,"王力宏") t.submit(fuc,'邻居家') #好处,可以添加循环 for i in range(100): t.submit(fuc,name =f"线程{i}") #把100任务给10个进程去处理
2、接受返回值
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time # #线程池 def fuc(name,t): time.sleep(t) print("我是" + name) return name def fn(res): print(res.result()) #打印结果 if __name__ == "__main__": with ThreadPoolExecutor(10)as t : t.submit(fuc,"周杰伦",1).add_done_callback(fn) t.submit(fuc,"王力宏",2).add_done_callback(fn) t.submit(fuc,'邻居家',3).add_done_callback(fn)
运行结果:
参数说明:
.add_done_callback(fn)是线程完成后,要返回,fn函数中res.result()取值;线程调用函数的时候不带()
fuc(name,t)包含两个参数 name 和时间t,return返回值
【如果没有时间t,t越大,最晚打印】返回callback执行的顺序是不确定的,返回值的顺序是不确定的
如何解决顺序的问题,可以采用map映射函数,函数结构如下
def map(self, fn, *iterables, timeout=None, chunksize=1):
pass
使用方法:
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time # #线程池 def fuc(name,t): time.sleep(t) print("我是" + name) return name def fn(res): print(res.result()) #打印结果 if __name__ == "__main__": with ThreadPoolExecutor(10)as t : # t.submit(fuc,"周杰伦",1).add_done_callback(fn) # t.submit(fuc,"王力宏",2).add_done_callback(fn) # t.submit(fuc,'邻居家',3).add_done_callback(fn) result = t.map(fuc,["周杰伦",'王力宏','邻居家'],[2,3,1]) print(result) for r in result: print(r)
map返回值是一个迭代器,返回的内容和任务分发的顺序是一致的,即无序的