多线程——python

一、添加线程
1.进程和线程
正在的运行的应用程序就是进程,进程和进程之间均运算在其专门的内存空间里面,相互独立不干扰
线程是进程执行任务的基本单元,一个进程默认有一个线程,这个线程叫主线程。
如果进程中需要主线程以外的线程(子线程),需要手动创建
2.threading模块
1)函数
threading是Python标准库中提供的专门处理多线程问题的模块。
threading.current_thread() - 获取当前线程
threading.active_count() - 获取当前进程的活跃线程个数
threading.enumerate() - 获取当前进程中所有的线程对象

2)类
Thread类 - Thread类的对象就是线程对象(程序需要多少个子线程,就需要创建多少个Thread类的对象)

# 获取当前线程
print(threading.current_thread())     # <_MainThread(MainThread, started 140736248673152)>

# 获取当前进程中活跃的线程的数量
print(threading.active_count())

# 获取当前进程中所有的线程对象
print(threading.enumerate())

3.添加线程 - 创建Thread对象
添加线程就是创建Thread的对象
1)创建线程
Thread(target=函数,args=元组) - 创建线程对象
target - 函数,需要在子线程执行的任务对应的函数
args - 元组,元组中的元素就是在子线程中调用target对应的函数传递的参数

2)启动线程
线程对象.start() - 在子线程中调用target对应的函数

def download_image(url: str):
    print('=====:', threading.current_thread())
    start = time.time()
    name = url[url.rindex('/'):]
    print(f'{name}开始下载: {datetime.now()}')
    response = requests.get(url)
    with open('files/'+name, 'wb') as f:
        f.write(response.content)
    time.sleep(2)
    end = time.time()
    print(f'{name}下载结束, {datetime.now()},所用时间{end-start}s')


# a.在主线程中下载三张图片
# download_image('https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1040146029,3829256909&fm=115&gp=0.jpg')
# download_image('https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1040146029,3829256909&fm=115&gp=0.jpg')
# download_image('https://dss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2414067779,1864517677&fm=26&gp=0.jpg')

# b.在三个子线程中下载三张图片
t1 = Thread(target=download_image, args=('https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1040146029,3829256909&fm=115&gp=0.jpg',))
t2 = Thread(target=download_image, args=('https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1040146029,3829256909&fm=115&gp=0.jpg',))
t3 = Thread(target=download_image, args=('https://dss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2414067779,1864517677&fm=26&gp=0.jpg',))
t1.start()
t2.start()
t3.start()


print('!!!!!:', threading.current_thread())

二、Thread的子类对象

class DownloadThread(Thread):
    def __init__(self, movie_name):
        super().__init__()
        self.movie_name = movie_name

    #  在run方法中实现需要在子线程中执行的任务。实现任务对应的功能需要额外的数据,不能传参,通过添加对象属性来提供数据
    def run(self):
        print(f'{self.movie_name}开始下载:{datetime.now()}')
        print('下载中....')
        print(self.movie_name[:])
        time.sleep(randint(2, 5))
        print(f'{self.movie_name}下载完成:{datetime.now()}')


movies = ['咒怨', 12, '八佰', '釜山行2', '活着']
ts = []
for m in movies:
    t = DownloadThread(m)
    t.start()
    ts.append(t)
    # 注意: run不能直接通过对象主动调用,否则任务都会在主线程中执行
    # t.run()

for t in ts:
    print(t.movie_name)


三、join
1.join
线程对象.join() - join后面的操作会在指定线程结束之后才执行

class DownloadThread(Thread):
    def __init__(self, movie_name):
        super().__init__()
        self.movie_name = movie_name

    #  在run方法中实现需要在子线程中执行的任务。实现任务对应的功能需要额外的数据,不能传参,通过添加对象属性来提供数据
    def run(self):
        print(f'{self.movie_name}开始下载:{datetime.now()}')
        print('下载中....')
        # print(self.movie_name[:])
        time.sleep(randint(2, 5))
        print(f'{self.movie_name}下载完成:{datetime.now()}')


t1 = DownloadThread('百变星君')
t2 = DownloadThread('美人鱼')
t3 = DownloadThread('回魂夜')
t1.start()
t2.start()
t3.start()

# =========在主线程中等待(电影下载完成前,主线程什么都不能做)============
# t1.join()
# t2.join()
# t3.join()
# print('电影都下载完成!')


# ==========在子线程中等待(电影下载完成前,主线程可以干其他的事情)
def wait():
    t1.join()
    t2.join()
    t3.join()
    print('==========电影下载完成!=============')


t4 = Thread(target=wait)
t4.start()


# =========
while True:
    print('=======')
    time.sleep(1)

四、queue的使用
注意: 在子线程中调用的函数没有返回值(有返回值也没有办法获取)
Queue提供的是线程安全的序列,专门用来保存不同线程中产生的数据,同时提供线程相关操作

计算nums中所有的数字的阶乘的和
nums = [6, 8, 4]

def factorial(num, result: Queue):
    re = reduce(lambda x, y: x*y, range(1, num+1), 1)
    # print(result)
    # return result
    time.sleep(2)
    # result.append(re)
    result.put({num: re})


# result = []
# 创建空队列
result = Queue()

t1 = Thread(target=factorial, args=(6, result))
t1.start()

t2 = Thread(target=factorial, args=(8, result))
t2.start()

t3 = Thread(target=factorial, args=(4, result))
t3.start()

t1.join()
t2.join()
t3.join()

# 取出结果
print(result.get())
print(result.get())
print(result.get())






五、51job数据爬取

from selenium import webdriver
from selenium.webdriver.common import keys
from pyquery import PyQuery as pq
import requests
import time
from threading import Thread

# 创建浏览器对象
browser = webdriver.Chrome()
# 指定浏览器打开的页面
browser.get('https://www.51job.com/')


def create_web_page():
    # 获取输入框
    input = browser.find_element_by_id('kwdselectid')
    # 在输入框中输入Python
    input.send_keys('Python')
    # 在输入框中按回车
    input.send_keys(keys.Keys.ENTER)
    # input.click()   # 点击指定标签

    # 通过浏览器获取页面内容
    doc = pq(browser.page_source)
    jobs_box = doc.find('.j_joblist>.e>.el')

    # 开始获取每个职位的详情页,并且获取职位信息
    start = time.time()
    all_thread = []
    for job in jobs_box:
        job_url = pq(job).attr('href')
        t = Thread(target=get_url, args=(job_url,))
        t.start()
        all_thread.append(t)
        # get_url(job_url)

    for t in all_thread:
        t.join()
    end = time.time()
    print(f'耗时:{end-start}')


# 通过requests获取指定页面的数据
def get_url(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36'
    }
    re = requests.get(url, headers=headers)
    # print(re.encoding)
    re.encoding = 'gbk'
    print('=================================================')
    # print(re.text)
    doc = pq(re.text)
    message_box = doc.find('.tCompany_main .tBorderTop_box:first-child')
    print(message_box.text())


def main():
    create_web_page()


if __name__ == '__main__':
    main()

    # headers = {
    #     'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36'
    # }
    # re = requests.get('https://jobs.51job.com/chengdu-qyq/119797173.html?s=01&amp;t=0', headers=headers)
    # print(re.encoding)
    # re.encoding = 'gbk'
    # print(re.text)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值