02、线程间通信

01、线程为什么需要通信

--线程会存在问题

02、多线程使用全局变量进行通信:使用上一个博客爬虫案例作为讲解案例

--为什么需要通信:
    --线程01:爬虫一个线程用于爬取主界面的url
    --线程02:取出爬取到的url进行解析进一步获取页面html详情

--使用 global定义全局变量【共享变量】  ||  使用参数传值的方式也行,因为python传递的是对象的引用

import threading
import time

url_list = []

def get_detail_html():
    # 根据获取到的url进一步访问界面,得到详细的html代码
    global url_list
    while True:
        if len(url_list):
            url = url_list.pop()

            print("get detail html_01 start")
            print(url)
            print("get detail html_01 and")
        else:
            break


def get_detail_url():
    # 获取主界面中的列表url,等待进一步访问
    global url_list

    while True:
        print("get detail html_02 start")
        for i in range(20):
            url_list.append("http://www.fund{}".format(i))
        print("get detail html_02 and")


if __name__ == '__main__':
    # 获取url
    thread_url = threading.Thread(target=get_detail_url)
    thread_url.start()

    # 多线程打印url
    for i in range(10):
        thread_html = threading.Thread(target=get_detail_html)
        thread_html.start()

03、多线程使用Queue进行通信

--除非你对 线程锁 足够了解,否则不推荐使用共享变量

--Queue:这里推荐使用,它可以使我们的线程按照规定的同步方式进行交互和通信
    --Queue对象及其属性都是线程安全的
    --线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
    --线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

--查看Queue的方法:点开pycharm左边和project一列的structure,可以看到对象的结构、变量和属性
    --put:put方法是往queue中压入数据
    --get: get方法是从queue中取出对象,Queue.get()时如果queue为空会使线程阻塞在此处,直至获取到数据
    --qsize: 获取队列的长度 Queue.qsize()
    --put_nowait 和 get_nowait:在从队列取数据 和 往队列放数据时,无需等待其执行结束就返回,这是一个异步方法

--Queue.put(item, block=True, timeout=None):
    --block: 表示设置是否等待队列操作完毕
    --timeout: 表示等待时间多长以后即刻返回

--使用队列进行通信的代码示例:
import threading
import time
from queue import Queue

def get_detail_html(queue):
    # 根据获取到的url进一步访问界面,得到详细的html代码
    while True:
        url = queue.get()
        print("get detail html_01 start")
        print(url)
        print("get detail html_01 and")


def get_detail_url(queue):
    # 获取主界面中的列表url,等待进一步访问
    while True:
        print("get detail html_02 start")
        for i in range(20):
            queue.put("http://www.fund{}".format(i))
        print("get detail html_02 and")


if __name__ == '__main__':
    # 申明队列 queue
    details_queue = Queue(maxsize=1000)

    # 获取url
    thread_url = threading.Thread(target=get_detail_url, args=(details_queue,))
    thread_url.start()

    # 多线程打印url
    for i in range(10):
        thread_html = threading.Thread(target=get_detail_html, args=(details_queue,))
        thread_html.start()

--成对使用 queue.task_done() 和 queue.join(),对程序进行控制

import threading
import time
from queue import Queue

len_url = 0
len_out = 0
def get_detail_html(queue):
    # 根据获取到的url进一步访问界面,得到详细的html代码
    while True:
        global len_out
        if queue.qsize() > 0:
            url = queue.get()
            print(url)
            len_out += 1
            print("len_out: {}".format(len_out))
        else:
            break
    queue.task_done()
    print("获取详情页结束啦!!!!!!!!!")



def get_detail_url(queue):
    # 获取主界面中的列表url,等待进一步访问
    while True:
        global len_url
        if len_url <= 1000:
            for i in range(1001):
                queue.put("http://www.fund{}".format(i))
                len_url += 1
            print("len_url: {}".format(len_url))
        else:
            break
    queue.join()
    print("生产者也结束啦###################")

if __name__ == '__main__':
    # 申明队列 queue
    details_queue = Queue(maxsize=1000)

    # 获取url
    thread_url = threading.Thread(target=get_detail_url, args=(details_queue,))
    thread_url.start()

    # 多线程打印url
    for i in range(10):
        thread_html = threading.Thread(target=get_detail_html, args=(details_queue,))
        thread_html.start()

    # # 队列阻塞
    # details_queue.task_done()
    # details_queue.join()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值