美文网首页
python多进程

python多进程

作者: Yznx_请叫我小哥 | 来源:发表于2019-03-11 22:28 被阅读0次
the photo from unsplash

python之多进程

写在前面

前面学习了多线程今天来学习一下多进程,相对于多线程,其实多进程的使用在日常生活中会使用更多,我们可以使用多进程来加速自己的爬虫。所以多进程是必须要学习的,但是其实多进程和多线程其实很相似,建议没有学习过多线程的先去将多线程学习一下。

什么是多进程

多进程 Multiprocessing 和多线程 threading 类似, 他们都是在 python 中用来并行运算的.

用多进程比多线程更加方便,我们为了方便所以使用多进程

开始多进程

多进程和多线程是真的很相似,建议先学多线程那样学这个也会很快的。

python的多进程支持

python是支持多进程的,而且是python的内置库,所以我们在使用的时候只需要将其引入就好,就像是这样:

import multiprocessing as mp

引入multiprocessing然后给它一个别名叫做mp,因为太长了后面不好使用所以起一个别名。

multiprocessing

常用函数:

myprocess = mp.Process() #添加一个新的进程,
myprocess.start()#开始一个新进程
myprocess.join() # 将进程加入阻塞

提示: 在使用的时候一定要记得加上main函数

进程池

这是一个新的概念,你可以使用进程池来快速生成进程。这个比线程要方便很多。
添加进程池:

import multiprocessing as mp
def job(x):
    return x**x
def multiprocess():
    pool = mp.Pool()
    res = pool.map(job, range(10))
    print(res)
if __name__ == '__main__':
    multiprocess()
"""
结果:
[1, 1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489]
"""

然后说到创建进程池就要详细讲述一下创建的方法和进程池的方法:
Pool函数
创建进程池的方法:其实很简单,但是像上面的那样去创建的话是使用你所有的进程,就是你有几个核心就创建相应的进程数,如果想要创建指定进程数的进程池的话可以在Pool函数中加上processes=2就像是这样“pool = Pool(processes=2)”
map函数
进程池的map函数,这是一个讲自己的任务分配给进程池的函数,job指定工作的函数,后面是一个参数
apply_async函数
如果你不想将所有将一个分开给进程任务传递参数那么你就需要apply_async函数,这个函数时只能传递一个参数:

res = pool.apply_async(job, (i,))

这里要注意的是参数必须传递一个可迭代对象,所以我们建议在传递的时候传递元祖类型的数据。
这样我们还可以将值取出来:

res.get()

这个时候如果你有新的想法,我想传递多个参数怎么办?那我们可以使用python中的生成器来传递参数,就像是这样:

res = [pool.apply_async(job, (i)) for i in range(10)]

当然在取值的时候也是需要一个一个的取出来。

实例

我在这里面呢爬取了豆瓣电影的top10,先演示普通的方法以及用时:

import multiprocessing as mp
from lxml import etree
import requests
import time

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit"
                        "/537.36 (KHTML, like Gecko) "
                        "Chrome/72.0.3626.121 Safari/537.36"}
r_url = "https://movie.douban.com/chart"

def crawl(surl):
   res = requests.get(url=surl, headers=headers).content.decode()
   response = etree.HTML(res)
   return response

def get_url_list(response):
   return response.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td[2]/div/a/@href')

def get_content(resonse):
   name = resonse.xpath('//*[@id="content"]/h1/span[1]//text()')
   author = resonse.xpath('//*[@id="info"]/span[1]/span[2]//text()')
   print(name, author)

if __name__ == '__main__':
   t1 = time.time()
   home = crawl(r_url)
   url_list = get_url_list(home)
   for url in url_list:
       now = crawl(url)
       get_content(now)
   print("use time:" , time.time()-t1)
"""
['谁先爱上他的 誰先愛上他的'] ['徐誉庭', ' / ', '许智彦']
['小偷家族 万引き家族'] ['是枝裕和']
['波西米亚狂想曲 Bohemian Rhapsody'] ['布莱恩·辛格']
['神奇动物:格林德沃之罪 Fantastic Beasts: The Crimes of Grindelwald'] ['大卫·叶茨']
['地球最后的夜晚'] ['毕赣']
['无敌破坏王2:大闹互联网 Ralph Breaks the Internet'] ['菲尔·约翰斯顿', ' / ', '瑞奇·摩尔']
['海王 Aquaman'] ['温子仁']
['宠儿 The Favourite'] ['欧格斯·兰斯莫斯']
['调音师 Andhadhun'] ['斯里兰姆·拉格万']
['摇摆狂潮 스윙키즈'] ['姜炯哲']
use time: 10.657264709472656
"""

我在这里的思路是首先获取到每一个电影的详情页面的URL,然后循环请求输出电影名称和导演,没做其他处理。
下面展示一下使用多进程的情况:

import multiprocessing as mp
from lxml import etree
import requests
import time

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit"
                        "/537.36 (KHTML, like Gecko) "
                        "Chrome/72.0.3626.121 Safari/537.36"}
r_url = "https://movie.douban.com/chart"

def crawl(surl):
   res = requests.get(url=surl, headers=headers).content.decode()
   response = etree.HTML(res)
   return response

def get_url_list(response):
   return response.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td[2]/div/a/@href')

def get_content(resonse):
   name = resonse.xpath('//*[@id="content"]/h1/span[1]//text()')
   author = resonse.xpath('//*[@id="info"]/span[1]/span[2]//text()')
   print(name, author)
   return (name, author)

if __name__ == '__main__':
   t1 = time.time()
   home = crawl(r_url)
   url_list = get_url_list(home)
   pool = mp.Pool()
   now_crawl = [pool.apply_async(crawl, (urls,)) for urls in url_list]
   contents = [j for j in now_crawl]
   cont = [pool.apply_async(get_content, (c,))for c in contents]
   cont = [k for k in cont]
   for s in cont:
       print(s)
   print("use time:" , time.time()-t1)
   '''
   (['谁先爱上他的 誰先愛上他的'], ['徐誉庭', ' / ', '许智彦'])
   (['小偷家族 万引き家族'], ['是枝裕和'])
   (['波西米亚狂想曲 Bohemian Rhapsody'], ['布莱恩·辛格'])
   (['神奇动物:格林德沃之罪 Fantastic Beasts: The Crimes of Grindelwald'], ['大卫·叶茨'])
   (['地球最后的夜晚'], ['毕赣'])
   (['无敌破坏王2:大闹互联网 Ralph Breaks the Internet'], ['菲尔·约翰斯顿', ' / ', '瑞奇·摩尔'])
   (['海王 Aquaman'], ['温子仁'])
   (['宠儿 The Favourite'], ['欧格斯·兰斯莫斯'])
   (['调音师 Andhadhun'], ['斯里兰姆·拉格万'])
   (['摇摆狂潮 스윙키즈'], ['姜炯哲'])
   use time: 3.403460741043091
   '''

然后至于为什么没输出值我也还在折腾,但是看一下使用的时间:第一个使用了10.7秒、第二个使用了3.0秒,这大概是3倍的差距,虽然这个因为爬取的东西比较少有一定水分但是还是有一定的差距,所以好好学习吧。

写在后面

当我在使用multiprocessing时遇到的坑
当我在使用的时候,我遇到了这样一个问题,那就是:

image.png
出现了这个错误,同时我被这个困扰了很久。最后终于找到了解决问题,那就是不要在函数中做一些数据处理,只要传递数据就好,其他的数据处理请在自定义函数中处理。上面那个代码就是错误示范,因为我是将数据处理后在函数中间传递,所以之前一直出现问题。关于正确的代码我会放在我的git中,欢迎去看:传送门

相关文章

网友评论

      本文标题:python多进程

      本文链接:https://www.haomeiwen.com/subject/ryaipqtx.html