python 复习—并发编程——进程数据共享进程锁进程池requests模块和bs4(beautifulsoup)模块

Posted 胖虎是只mao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 复习—并发编程——进程数据共享进程锁进程池requests模块和bs4(beautifulsoup)模块相关的知识,希望对你有一定的参考价值。

一、进程

1、进程间数据不共享每个进程都有自己的一个列表,如下示例:

	import multiprocessing
    data_list = []
    def task(arg):
        data_list.append(arg)
        print(data_list)  # 每个进程都有自己的一个列表

    def run():
        for i in range(10):
            p = multiprocessing.Process(target=task,args=(i,))
            p.start()

    if __name__ == '__main__':
        run()

2、进程的常用功能
join(6)等待进程完成,最多等6秒

	import multiprocessing
    import time

    def task(arg):
        time.sleep(2)
        print(arg)

    def run():
        print(11111111)
        p1 = multiprocessing.Process(target=task,args=(1,))
        p1.start()
        p1.join(6)  # 等待进程完成,最多等6秒
        print(22222222)

        p2 = multiprocessing.Process(target=task,args=(2,))
        p2.start()
        p2.join()
        print(33333333)

    if __name__ == '__main__':
        run()

join

p1.daemon = False # 等待进程完成,默认

	import multiprocessing
    import time

    def task(arg):
        time.sleep(2)
        print(arg)

    def run():
        print(11111111)
        p1 = multiprocessing.Process(target=task,args=(1,))
        p1.daemon = False  # 等待进程完成,默认
        p1.start()
        print(22222222)

        p2 = multiprocessing.Process(target=task,args=(2,))
        p2.daemon = True  # 不等进程完成
        p2.start()
        print(33333333)

    if __name__ == '__main__':
        run()

daemon

p = multiprocessing.current_process() # 获取当前进程
name = p.name 获取当前进名称
id1 = p.ident # 获取进程id
id2 = p.pid # 获取进程id

	import multiprocessing
    import time

    def task(arg):
        time.sleep(2)
        p = multiprocessing.current_process()  # 获取当前进程
        name = p.name
        id1 = p.ident  # 获取进程id
        id2 = p.pid  # 获取进程id
        print(arg,name,id1,id2)

    def run():
        print(11111111)
        p1 = multiprocessing.Process(target=task,args=(1,))
        p1.name = 'pp1'  # 为进程设置名字pp1
        p1.start()
        print(22222222)

        p2 = multiprocessing.Process(target=task,args=(2,))
        p2.name = 'pp2'  # 为进程设置名字pp2
        p2.start()
        print(33333333)

    if __name__ == '__main__':
        run()

name / current_process() / ident/pid

二、数据共享(内存级别)

线程安全多个线程同时并发的访问数据,不会出现冲突

1、Queue

linux示例:

	import multiprocessing

    q = multiprocessing.Queue()
    def task(arg,q):
        q.put(arg)

    def run():
        for i in range(10):
            p = multiprocessing.Process(target=task, args=(i, q,))
            p.start()

        while True:
            v = q.get()
            print(v)
    run()


import multiprocessing
    def task(arg,q):
        q.put(arg)

    if __name__ == '__main__':
        q = multiprocessing.Queue()
        for i in range(10):
            p = multiprocessing.Process(target=task,args=(i,q,))
            p.start()
        while True:
            v = q.get()
            print(v)

windows示例:

在这里插入图片描述
put()get() 方法都是阻塞的

get() 会卡住,直到有数据取出来
put() 当队列满了之后,会卡住,知道有空闲的位置之后,才能put进去

2、Manager

	import multiprocessing
    m = multiprocessing.Manager()
    dic = m.dict()

    def task(arg):
        dic[arg] = 100

    def run():
        for i in range(10):
            p = multiprocessing.Process(target=task, args=(i,))
            p.start()
        input('>>>')
        print(dic.values())

    if __name__ == '__main__':
        run()

linux示例:
	import multiprocessing
    import time

    def task(arg,dic):
        time.sleep(2)
        dic[arg] = 100

    if __name__ == '__main__':
        m = multiprocessing.Manager()
        dic = m.dict()

        process_list = []
        for i in range(10):
            p = multiprocessing.Process(target=task, args=(i,dic,))
            p.start()
            process_list.append(p)

        while True:
            count = 0
            for p in process_list:
                if not p.is_alive():  # 如果某进程已经执行完毕,则count加1
                    count += 1
            if count == len(process_list):
                break
        print(dic)

windows示例:

三、进程锁

进程锁同线程锁的种类和用法一样,参见线程锁。如下是进程锁RLock示例:

	import time
    import multiprocessing

    lock = multiprocessing.RLock()

    def task(arg):
        print('鬼子来了')
        lock.acquire()
        time.sleep(2)
        print(arg)
        lock.release()

    if __name__ == '__main__':
        p1 = multiprocessing.Process(target=task,args=(1,))
        p1.start()

        p2 = multiprocessing.Process(target=task, args=(2,))
        p2.start()

问题1:为什么要加进程锁?

线程锁是为了在线程不安全的时候,为一段代码加上锁来控制实现线程安全,即线程间数据隔离

进程间的数据本来就是隔离的,所以一般不用加锁当进程间共用某个数据的时候需要加锁

四、进程池

	import time
    from concurrent.futures import ProcessPoolExecutor

    def task(arg):
        time.sleep(2)
        print(arg)

    if __name__ == '__main__':
        pool = ProcessPoolExecutor(5)  # 创建一个进程池
        for i in range(10):
            pool.submit(task,i)

五、requests模块和bs4(beautifulsoup)模块 – (初识爬虫)

1、安装:

   pip3 install requests

   pip3 install beautifulsoup4

2、示例代码(爬取抽屉网的标题和链接):

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

    # 模拟浏览器发送请求
    # 内部创建 sk = socket.socket()
    # 和抽屉进行socket连接 sk.connect(...)
    # sk.sendall('...')
    # sk.recv(...)
    def task(url):
        print(url)
        r1 = requests.get(
            url=url,
            headers={
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
            }
        )
        # 查看下载下来的文本信息
        soup = BeautifulSoup(r1.text,'html.parser')
        # print(soup.text)
        content_list = soup.find('div',attrs={'id':'content-list'})
        for item in content_list.find_all('div',attrs={'class':'item'}):
            title = item.find('a').text.strip()
            target_url = item.find('a').get('href')
            print(title,target_url)

    def run():
        pool = ThreadPoolExecutor(5)
        for i in range(1,50):
            pool.submit(task,'https://dig.chouti.com/all/hot/recent/%s' %i)

    if __name__ == '__main__':
        run()

总结:

   1)以上示例进程和线程哪个好?

          线程好,因为socket属于IO请求,不占用CPU,所以用多线程即节省资源又提高效率;

   2)requests模块模拟浏览器发送请求:

          requests.get( . . . ) 本质:

                 创建socket客户端

                 连接【阻塞】

                 发送请求

                 接收请求【阻塞】

                 断开连接

以上是关于python 复习—并发编程——进程数据共享进程锁进程池requests模块和bs4(beautifulsoup)模块的主要内容,如果未能解决你的问题,请参考以下文章

python 复习—并发编程系统并发线程和进程协程GIL锁CPU/IO密集型计算

python并发编程之多进程:互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型

Python并发编程-进程间数据共享

Python之路(第三十八篇) 并发编程:进程同步锁/互斥锁信号量事件队列生产者消费者模型

python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式

python并发编程之多进程1------互斥锁与进程间的通信