爬虫-多线程和线程池

一、多线程

  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返回值是一个迭代器,返回的内容和任务分发的顺序是一致的,即无序的

posted @ 2024-01-15 22:45  zhang0513  阅读(11)  评论(0编辑  收藏  举报