西刺代理爬虫多进程改进验证有效代理IP

吐槽
   作为一名小白,初次写的爬虫,对于性能、耗时等等完全不在意。但是之前写的验证100个proxyIp的有效性
话的时间是在无法接受470秒。在被逼无奈的情况下,用多进程改进,但是途中闹了很多笑话,这里记录一下。
背景

模块:
1. multiprocessing.Pool (PS:就在网上查了一下用进程池的比较多。这里就介绍一下简单的用法,详细介绍请自行查文档)

def func(param):
    return param
pool = Pool(4)  #参数可选,不填默认cpu的核数。
for i in range(10):
    pool.apply_async(func, args=(param,))#异步开启子进程
pool.close()    #pool必须先关闭
pool.join()     #等待全部进程结束
错误示范
  1. 自以为是的认为进程池中的进程可以共享list对象变量。
def valid_proxy(proxy, proxy_list):
    #验证有效性
    proxy_list.append(proxy)

pool = Pool(8)
for proxyIp in proxy_list:
    pool.apply_async(valid_proxy, args=(proxy, proxy_list))
pool.close()
pool.join()
PS:刚开始把进程相关的全还给老师啦,以为是python函数的传递参数的问题。
结论:**普通的全局变量不能被子进程所共享**

2. 对python函数参数传递的错误理解。(这个很突兀,主要是我在写代码的随便冒出来的)

这里简单的总结记录:python中分变量和对象。
    1. 对象分为不可变对象(number, string, tuple),可变对象(list, dict)
    2. 变量保存的是对象的地址。

**结论:python函数参数传递传的是变量所保存的对象的地址。**
PS:
1. 用type(var)判断变量保存的对象的类型
2. 用id(var)查看变量保存的对象的地址。
这里给个例子解释一下为什么我想当然认为进程可以共享变量
from multiprocessing import Pool

def print_id(proxy, proxy_list):
    print(type(proxy_list))
    print(id(proxy_list))
    proxy_list.append(proxy)

if __name__ == '__main__':
    proxy_list = [] #全局变量(并不是真正意义上的)
    pool = Pool(4)
    for i in range(10):
        pool.apply_async(print_id, args=(i, proxy_list))
    pool.close()
    pool.join()
    print(proxy_list)
  这里id(list)的输出同是同一个地址,我想当然的觉得可以这么写。但是print(list)却是[]空的,在这里
  联系一下linux中的fork的原理,fork会将复制父进程的内存空间。加上虚拟地址概念,
  导致这里id(list)输出都是同一个地址。(纯属瞎猜,有大神了解详情请指教。)所以得出了上述结论。
正确展示(自以为的)
  1. 经过上述的错误经历,差不多快回忆起,好像还有一个共享内存的概念了。之后就查了和Pool相关的Manager。这里简单介绍一下multiprocessing.Manager可以创建适用Pool的共享变量。

    from multiprocessing import Pool, Lock, Manager
    
    def print_id(proxy, proxy_list):
        print(type(proxy_list))
        print(id(proxy_list))
        proxy_list.append(proxy)
    
    if __name__ == '__main__':
        pool = Pool(4)
        proxy_list = Manager().list()
        for i in range(10):
            pool.apply_async(print_id, args=(i, proxy_list))
        pool.close()
        pool.join()
        print(proxy_list)
    PS:申明一下小白,在这里并没有苛刻性能,因为这个在windows下,多进程只能在main函数中,
    所以就会涉及到将Manager对象传递给实例化的子进程。但是这个过程会消耗巨大资源,性能比较差。
    而且大家都说在使用多进程的过程中,最好不要使用共享资源。这个版本是我之后写的。
    
  2. 在发现传值行不通的情况下,我果断的选择了保存每个进程的返回值。代码如下

from multiprocessing import Pool

def print_id(proxy):
    return proxy
if __name__ == '__main__':
    pool = Pool(4)
    proxy_list = []
    for i in range(10):
        proxy_list.append(pool.apply_async(print_id, args=(i,)))
    pool.close()
    pool.join()
    for i in proxy_list:
        print(i.get())#这里需要注意get函数必须在进程运行完毕才能使用

PS:其实也没有太过较真这两种方案的性能。以本人这种浅薄的功力,实在太过无奈。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值