Day28-多进程和线程池

Day28-多进程和线程池

1、多进程

from threading import Thread
01、多进程
一个应用程序默认有一个进程(主进程),一个进程中默认有一个线程(主线程)。
一个应用程序可以有多个进程,每个进程中也可以有多个线程。
同一个进程中的多个线程之间数据可以直接共享;不同进程中的数据无法直接共享
同一个进程中的多个线程之间数据可以直接共享
 def func1():
     global a
     a = 100
     data.append(10)


 def func2():
     global b
     b = 200
     print(a)
     data.append(20)


 if __name__ == '__main__':
     data = []
     t1 = Thread(target=func1)
     t2 = Thread(target=func2)
     t1.start()
     t2.start()

     print(a, b)
     print(data)

# 多进程基本用法
from multiprocessing import Process, current_process
from datetime import datetime
import time, random
02、多进程的使用
一个程序默认只有一个进程,如果需要多个进程,需要程序员手动创建进程对象:
进程对象 = Process(target=函数, args=元组)
进程对象.start()
进程对象.join()
 def download(name):
     print(f'======{name}开始下载:{datetime.now()}')
     print(current_process())
     time.sleep(random.randint(2, 7))
     print(f'======{name}下载结束:{datetime.now()}')


 # 多进程程序中下面这个if语句必须添加
 if __name__ == '__main__':
     p1 = Process(target=download, args=('肖申克的救赎',))
     p2 = Process(target=download, args=('阿甘正传',))
     p3 = Process(target=download, args=('霸王别姬',))
     p1.start()
     p2.start()
     p3.start()

     p1.join()
     p2.join()
     p3.join()
     print('全部下载完成!')


# 不同进程中的数据无法直接共享
def func1():
    global a
    a = 100
    data.append(10)



def func2():
    global b
    b = 200
    # print(a)
    data.append(20)


if __name__ == '__main__':
    data = []
    p1 = Process(target=func1)
    p2 = Process(target=func2)
    p1.start()
    p2.start()

    p1.join()
    p2.join()
    print(data)

2、线程池

from threading import Thread, current_thread
from concurrent.futures import ThreadPoolExecutor
import time
from random import randint
from datetime import datetime


def download(name):
    print(f'======{name}开始下载:{datetime.now()}')
    print(current_thread())
    time.sleep(randint(2, 7))
    print(f'======={name}下载结束:{datetime.now()}')


 1. 没有线程池(了解)
 if __name__ == '__main__':
     # 下载1000个电影,同时可以有10个一起下载
     for count in range(100):
         ts = []
         for x in range(10):
             t = Thread(target=download, args=(f'电影{count*10+x}',))
             t.start()
             ts.append(t)
         for t in ts:
             t.join()
         print(f'{count}波完成')


# 2. 线程池的使用
# 1)创建线程池对象
pool = ThreadPoolExecutor(5)

# 2)添加任务
# a.一次添加一个任务: 线程池对象.submit(函数,实参1,实参2,...)
pool.submit(download, '肖申克的救赎')
for x in range(10):
    pool.submit(download, f'电影{x}')

# b.一次添加多个任务: 线程池对象.map(函数, [数据1, 数据2, 数据3,...])
# 注意:这个地方任务对应的函数必须是有且只有一个参数的函数
pool.map(download, ['霸王别姬', '阿甘正传', '触不可及'])

# 注意:只要线程池没有关闭,我们可以在任何你需要的位置添加任务。

# 3)关闭线程池(同时具备关闭线程池和等待线程池任务都完成的功能)
pool.shutdown()
# pool.submit(download, '电影10')         # 报错!
print('全部任务都完成!')

3、线程池亚马逊

import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor


def get_goods_list(page, name='防晒霜'):
    """
    获取一页商品列表
    :param page: 页数,从1开始
    :param name: 商品名称
    :return:
    """
    # 1. 获取网页数据
    url = f'https://www.amazon.cn/s?k={name}&page={page}'
    headers = {
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'
    }
    response = requests.get(url, headers=headers)

    # 2. 解析数据
    soup = BeautifulSoup(response.text, 'lxml')
    goods_div_list = soup.select('.s-result-item')
    all_url = []
    for div in goods_div_list:
        goods_url = div.attrs['data-asin']
        if goods_url:
            all_url.append('https://www.amazon.cn/dp/' + goods_url)
    print(f'第{page}页数据获取完成')
    return all_url


def get_goods_info(goods_url):
    """
    获取指定地址对应的商品信息
    :param goods_url: 商品详情地址
    :return: None
    """
    print('----商品详情开始获取----')
    headers = {
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'
    }
    response = requests.get(goods_url, headers=headers)

    soup = BeautifulSoup(response.text, 'lxml')
    title = soup.select_one('#productTitle').text.strip()
    price = soup.select_one('.a-price>.a-offscreen').text.strip()
    print(title, price)


if __name__ == '__main__':
    # 1. 创建两个线程池
    list_pool = ThreadPoolExecutor(5)       # 获取所有商品列表数据的线程池
    info_pool = ThreadPoolExecutor(50)      # 获取商品详情数据的线程池

    # 2. 添加任务
    # map函数的返回值是一个生成器,生成器中的数据就是任务函数的返回值
    result = list_pool.map(get_goods_list, range(1, 11))

    for x in result:
        info_pool.map(get_goods_info, x)

4、线程队列

from threading import Thread
from concurrent.futures import ThreadPoolExecutor
import time
from datetime import datetime
from random import randint

# 1. 线程队列的使用
from queue import Queue
"""
使用队列的方法:
1)创建队列对象:Queue()
2)添加数据:队列对象.put(数据)
3)获取数据:队列对象.get() 、队列对象.get(timeout=超时时间)
          如果队列是空,队列的get操作不会报错,并且会进入等待状态,等到有数据进入队列为止
"""



def download(name):
    print(f'----{name}开始下载----')
    time.sleep(randint(2, 7))
    print(f'----{name}下载结束----', datetime.now())

    # 电影数据
    # all_data.append(f'{name}数据')

    # return f'{name}数据'

    q.put(f'{name}数据')


if __name__ == '__main__':

    # 方法1的列表
    all_data = []
    # 方法3的队列
    q = Queue()

    pool = ThreadPoolExecutor(5)
    result = pool.map(download, [f'电影{x}' for x in range(20)])

    # ====在主线程获取所有的下载结果====
    # ------------------方法1 - 不管是线程池还是直接使用多个线程都有效------------
    # 1)在主线程中创建列表,然后在子线程中直接往列表中添加数据
    # 2)等所有任务都完成后获取数据
    # pool.shutdown()
    # print(all_data)

    # ------------------方法2 - 线程池有效------------
    # 1)将子线程中产生的数据作为函数的返回值
    # 2)获取map函数的返回值(返回值是一个生成器,生成器中的元素就是每次调用函数,函数的返回值)
    # for x in result:
    #     print(x, datetime.now())

    # ----------------方法3  -  线程池和直接使用多线程都有效-----------
    # 1)在主线程中创建一个队列
    # 2)在子线程中往队列中添加数据
    # 3)在主线程中获取队列中的数据
    for _ in range(20):
        print(q.get(), datetime.now())

5、队列的使用方法

from queue import Queue
from threading import Thread

# q = Queue()
# # q.put(100)
# print(q.get())
#
# print('end!')

def func1():
    value = input('请输入数据:')
    q.put(value)


if __name__ == '__main__':
    q = Queue()

    t = Thread(target=func1)
    t.start()

    print(q.get())
    print('end!')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值