并发,并行,线程,进程,GIL锁

1.并发和并行

  并发:

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

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

  并行:

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

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

  解决并发:

  1.队列:即排队

   缓冲区:排成的队列

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

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

扫描二维码关注公众号,回复: 3120998 查看本文章

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

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

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

猜你喜欢

转载自www.cnblogs.com/s593941/p/9622939.html
今日推荐