zoukankan      html  css  js  c++  java
  • 并发,并行,线程,进程,GIL锁

    1.并发和并行

      并发:

        同时做某些事,但是强调同一时段做多件事

        如:同一路口,发生了车辆要同时通过路面的时间.

      并行:

        互不干扰的在同一时刻做多件事

        如:同一时刻,同时有多辆车在多条车道上跑,即同时发生的概念.

      解决并发:

      1.队列:即排队

       缓冲区:排成的队列

      2.争抢:锁机制,在同一时刻CPU只能为一个进程服务

      3.并行:开启多个CPU,同时提供服务

    在电脑中,如果并发,由于执行速度特别快,所以人感觉不到停顿,认为是同时进行的.

         如果并行,就是同时进行的,即创建多个同时操作

    2.进程和线程

      a.在实现了线程的操作系统中,线程是操作系统能够运算调度的最小单位.

      b.线程被包含在进程中,是进程的实际运作单位.

      c.一个程序的执行实例就是一个进程.

      d.一个应用程序(软件)可以有多个进程(默认只有一个),一个进程可以有多个线程(默认只有一个).

     2.1进程

      进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.进程是线程的容器.

      当运行一个程序时,OS会创建一个进程,它会使用系统资源(CPU,内存和磁盘空间)和OS内核中的数据结构(文件,网络连接,用量统计等).

      进程之间是互相隔离的,即一个进程无法访问其他进程中的内容,也无法操作其他进程.

      操作系统会跟踪所有正在运行的进程,给每个进程一小段运行时间,然后切换到其他进程,这样既可以做到公平又可以响应用户操作.

      2.2线程

        进程是独立的,进程间不能随便共享数据

        线程是进程中的,同一进程内的线程可以共享进程的资源,每一个线程有自己独立的堆栈.

      线程的状态:

        就绪:线程一旦运行,就在等待被调度.

        运行:线程正在运行

        阻塞:线程等待外部事件发生而无法运行,如I/O操作.

        终止:线程完成或退出,或被取消.

    python中的线程:

      python线程开发使用threading库

    1 def __init__(self,group=None,target=None,name=None,args=(),kwargs=None,*,daemon=None)

    target:线程调用的对象,就是目标函数

    name:为线程起的名字

    args:为目标函数传递实参,元组

    kwargs:为目标函数关键字传参,字典.

      1.线程的基本使用:

    1 import threading
    2 
    3 def func(arg):
    4     print(arg)
    5 
    6 t = threading.Thread(target=func,args=(11,))
    7 t.start()

      2.主线程默认等子线程执行完毕

     1 import time
     2 import threading
     3 
     4 def func(arg):
     5     time.sleep(arg)
     6     print(arg)
     7 
     8 t1 = threading.Thread(target=func,args=(3,))
     9 t1.start()
    10 
    11 t2 = threading.Thread(target=func,args=(9,))
    12 t2.start()
    13 print(123)

      3.主线程不再等,主线程终止则所有子线程终止

     1 import time
     2 import threading
     3 
     4 def func(arg):
     5     time.sleep(2)
     6     print(arg)
     7 
     8 t1 = threading.Thread(target=func,args=(3,))
     9 t1.setDaemon(True)
    10 t1.start()
    11 
    12 t2 = threading.Thread(target=func,args=(9,))
    13 t2.setDaemon(True)
    14 t2.start()
    15 
    16 print(123)

      4.控制主线程等待子线程(最多等待时间)

     1 import threading
     2 import time
     3 
     4 def func(arg):
     5     time.sleep(0.1)
     6     print(arg)
     7 
     8 print("创建子线程t1")
     9 
    10 t1 = threading.Thread(target=func,args=(3,))
    11 t1.start()
    12 t1.join(2)
    13 
    14 print("创建子线程t2")
    15 t2 = threading.Thread(target=func,args=(9,))
    16 t2.start()
    17 t2.join(2)
    18 
    19 print(123)
    20 
    21 #join中无参数,让主线程在这里等着,等到子线程t1执行完毕,才继续往下走
    22 #join中有参数,让主线程在这里最多等待n秒,无论是否执行完毕,都会继续往下走

      5.线程名称

     1 import threading
     2 
     3 def func(arg):
     4     #获取当前执行该函数的线程的对象
     5     t = threading.current_thread()
     6     #根据当前线程对象获取当前线程名称
     7     name = t.getName()
     8     print(name,arg)
     9 
    10 t1 = threading.Thread(target=func,args=(1,))
    11 t1.setName("1")
    12 t1.start()
    13 
    14 t2 = threading.Thread(target=func,args=(2,))
    15 t2.setName("2")
    16 t2.start()
    17 
    18 print(123)

    t.start()并不是开始运行线程,而是告诉CPU已经准备就绪,可以调度了.

      6.面向对象版本的多线程

     1 import threading
     2 
     3 #多线程方式1:
     4 def func(arg):
     5     print(arg)
     6 
     7 t1 = threading.Thread(target=func,args=(111,))
     8 t1.start()
     9 
    10 #多线程方式2:
    11 class MyThread(threading.Thread):
    12     
    13     def run(self):
    14         print(111,self._args,self._kwargs)
    15 
    16 t1 = MyThread(args=(11,))
    17 t1.start()
    18 
    19 t2 = MyThread(args=(22,))
    20 t2.start()
    21 
    22 print("end")

    python多线程情况下:

      计算密集型操作:效率低(GIL锁)

      IO操作:效率高

    python多进程的情况下:

      计算密集型操作:效率高(浪费资源)

      IO操作:效率高(浪费资源)

    一般写时:

      IO密集型用多线程:文件/输入输出/socket网络通信

      计算密集型用多进程

    Java多线程情况下:

      计算密集型操作:效率高

      IO操作:效率高

    Python多进程的情况下:

      计算密集型操作:效率高(浪费资源)

      IO操作:效率高,浪费资源

    3.GIL锁

      GIL锁,全局解释器锁,用于限制一个进程中同一时刻只有一个线程被CPU调度,默认GIL锁在执行100个CPU指令.

      多进程可以充分使用CPU的两个内核,而多线程却不能充分使用CPU的两个内核.

      原因:cpython解释器中存在GIL(全局解释器锁),它的作用就是保证同一时刻只有一个线程可以执行代码.

      因此造成了使用多线程的时候无法实现并行.

      解决方案:

        1.更换解释器,比如使用jpython(java实现的python解释器)

        2.使用多进程完成多任务的处理

    常见GIL面试题:

      描述Python GIL的概念,以及它对python多线程的影响,并阐明多线程抓取程序是否可比单线程性能有提升,并解释原因

      python语言和GIL没有关系,仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL.

      GIL:全局解释器锁.每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程可以执行代码.

      线程释放GIL锁的情况:在IO操作等可能会引起阻塞的syste, call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL

      python使用多进程是可以利用多核的CPU资源的.

      多线程爬去比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁.

    结论:

      1.在处理像科学计算这类需要持续使用CPU的任务的时候,单线程会比多线程快.

      2.在处理像IO操作等可能引起阻塞的这类任务的时候,多线程会比单线程快.

     1 import time
     2 import threading
     3 
     4 lock = threading.Rlock()
     5 n = 10
     6 
     7 def task(i):
     8     print("这段代码不加锁",i)
     9     lock.acquire()    #加锁, 此区域的代码同一时刻只能由一个线程执行.
    10     global n
    11     print("当前线程",i,"修改n值为:",n)
    12     lock.release()    #释放锁
    13 
    14 for i in range(10):
    15     t = threading.Thread(target=task,args=(i,))
    16     t.start()
  • 相关阅读:
    python爬取糗事百科段子
    python爬虫-韩寒新浪博客博文
    python-函数
    Python-列表
    Linux学习笔记001——win下安装Linux虚拟机
    python爬虫-正则表达式
    IIS使用十大原则,(IIS过期时间,IIS缓存设置) 【转载】
    在mysql 中两种锁定问题
    php 迭代器与和生成器
    DBCP连接池使用问题
  • 原文地址:https://www.cnblogs.com/s593941/p/9622939.html
Copyright © 2011-2022 走看看