进程相关

一.进程和线程的区别 或者GIL锁

  1.进程是cpu资源分配的最小单元

   线程是cpu计算的最小单元

  2.一个进程中可以有多个线程

  3.对于python来说他的进程和线程和其他语言有差异, 是有GIL锁.

   GIL锁保证一个进程中同一时刻只有一个线程被cpu调度.

  IO密集型操作可以使用多线程, 计算密集型操作可以使用多进程.

二.进程

  进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

  操作系统引入进程的概念的原因

从理论角度看,是对正在运行的程序过程的抽象;

从实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。

 进程的特征
动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
并发性:任何进程都可以同其他进程一起并发执行
独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
结构特征:进程由程序、数据和进程控制块三部分组成。
多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
 进程与程序的区别
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
程序可以作为一种软件资料长期存在,而进程是有一定生命期的。
程序是永久的,进程是暂时的。

  进程间的数据不共享

1.进程间的通信应该尽量避免共享数据的方式

2.进程间的数据是独立的,可以借助队列或管道实现通信,二者都是基于消息传递的。虽然进程间数据独立,但可以用过Manager实现数据共享

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 = threading.Thread(target=task,args=(i,))
        p.start()
if __name__ == '__main__':
    run()
#结果
  [2]
  [0]
  [1]
  [3]
  [8]
  [5]
  [6]
  [7]
  [4]
  [9]

进程的常用功能

  join    

    无参数,让主线程在这里等着,等到子线程t1执行完毕,才可以继续往下走
    有参数,让主线程在这里最多等待n秒,无论是否执行完毕,会继续走下去

  deamon    设置为后台线程或前台线程(默认)
                    如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                    如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

  name    

    setName      为线程设置名称

    getName      获取线程名称

  multiprocessing.current_process()      获取当前执行该函数的线程的对象

  multiprocessing.current_process().ident/pid     获取当前执行该函数的线程的ID

import time
import multiprocessing
def task(arg):
    p = multiprocessing.current_process()
    print(p.name)
    time.sleep(2)
    print(arg)
def run():
    print('111111111')
    p1 = multiprocessing.Process(target=task,args=(1,))
    p1.name = 'pp1'
    p1.start()
    print('222222222')
    p2 = multiprocessing.Process(target=task, args=(2,))
    p2.name = 'pp2'
    p2.start()
    print('333333333')
if __name__ == '__main__':
    run()
#结果:111111111
     222222222
   333333333
   pp1
   pp2
   1
   2    

通过类继承方式创建进程

import multiprocessing
class MyProcess(multiprocessing.Process):
    def run(self):
        print('当前进程',multiprocessing.current_process())
def run():
        p1 = MyProcess()
        p1.start()
        p2 = MyProcess()
        p2.start()
if __name__ == '__main__':
    run()
#结果:当前进程 <MyProcess(MyProcess-1, started)>
     当前进程 <MyProcess(MyProcess-2, started)>

进程间的数据共享

  进程之间的通信有两种实现方式:管道和队列


from multiprocessing import Manager,Process,Lock
def work(dic,mutex):
    # mutex.acquire()
    # dic['count']-=1
    # mutex.release()
    # 也可以这样加锁
   with mutex:
        dic['count'] -= 1
if __name__ == '__main__':
    mutex = Lock()
    m = Manager()  #实现共享,由于字典是共享的字典,所以得加个锁
    share_dic = m.dict({'count':100})
    p_l = []
    for i in range(100):
        p = Process(target=work,args=(share_dic,mutex))
        p_l.append(p)  #先添加进去
        p.start()
    for i in p_l:
        i.join()
    print(share_dic)
 # 共享就意味着会有竞争,

三.进程锁

  Lock

  RLock  (一次放一个)( 递归锁 )

  BoundedSemaphore(1次放N个)信号量

  条件(Condition)(1次放动态N个)

  事件Event(1次放所有)

import time
import threading
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()

为什么要加锁

  因数据共享

四.进程池

在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。多进程是实现并发的手段之一,需要注意的问题是:

  1. 很明显需要并发执行的任务通常要远大于核数
  2. 一个操作系统不可能无限开启进程,通常有几个核就开几个进程
  3. 进程开启过多,效率反而会下降(开启进程是需要占用系统资源的,而且开启多余核数目的进程也无法做到并行)

那么什么是进程池呢?  进程池就是控制进程数目

创建进程池的类:如果指定numprocess为3,则进程池会从无到有创建三个进程,然后自始至终使用这三个进程去执行所有任务,不会开启其他进程

import time
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
def task(arg):
    time.sleep(2)
    print(arg)
if __name__ == '__main__':
    pool = ProcessPoolExecutor(5)
    for i in range(10):
        pool.submit(task,i)

五.初始爬虫

  1.安装:

    pip3 install requests

    pip3 install beautifulsoup4

 

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()
示例

 

 相关:

  a.以上示例进程和线程哪个好?
    线程好

  b.requests 模块模拟浏览器发送请求

    本质 requests.get():

      创建socket客户端

      连接 (阻塞)

      发送请求

      接收请求 (阻塞)

      断开连接

  c.线程和进程池

posted @ 2018-09-12 17:23  Montant  阅读(126)  评论(0编辑  收藏  举报