进程/线程/协程/GIL

线程

线程是操作系统调度的最小单位

threading模块

线程的调用方式:

import threading
import time

‘‘‘直接调用‘‘‘

def hello(name):
    print("Hello %s"%name)
    time.sleep(3)

if __name__ == "__main__":
    t1=threading.Thread(target=hello,args=("zhangsan",)) #生成线程实例
    t2=threading.Thread(target=hello,args=("lisi",))

    t1.setName("aaa")   #设置线程名
    t1.start()  #启动线程
    t2.start()
    t2.join()   #join  等待t2先执行完
    print("Hello")
    print(t1.getName()) #获取线程名

setDaemon线程

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
import threading
def run(n):
    print(‘Hello..[%s]\n‘ % n)
    time.sleep(2)

def main():
    for i in range(5):
        t = threading.Thread(target=run,args=[i,])
        t.start()
        t.join(1)

m = threading.Thread(target=main,args=[])
m.setDaemon(True) #将主线程设置Daemon设置为True后,主线程执行完成时,其它子线程会同时退出,不管是否执行完任务
m.start()
print("--- done----")

线程锁Lock

import threading
import time

num = 100 #设置一个共享变量
lock=threading.Lock()  #生成全局锁
def show():
    global num  #在函数内操作函数外变量,需设置为全局变量
    time.sleep(1)
    lock.acquire()  #修改前加锁
    num -= 1
    lock.release()  #修改后解锁
list=[]
for i in range(100):
    t = threading.Thread(target=show)
    t.start()
    list.append(t)

for t in list:
    t.join()

print(num)

进程

multiprocessing模块

from multiprocessing import Process
import time

def start(name):
    time.sleep(1)
    print(‘hello‘, name)

if __name__ == "__main__":
    p = Process(target=start, args=(‘zhangsan‘,))
    p1 = Process(target=start, args=(‘lisi‘,))
    p.start()
    p1.start()
    p.join()
    

进程间通讯

  每个进程都拥有自己的内存空间,因此不同进程间内存是不共享的,要想实现两个进程间的数据交换,有几种方法

Queue(队列)

from multiprocessing import Process, Queue

def start(q):
    q.put(‘hello‘)

if __name__ == "__main__":
    q = Queue()
    p = Process(target=start, args=(q,))
    p.start()
    print(q.get())
    p.join()

协程

协程,又称微线程,是一种用户态的轻量级线程。协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置,当程序中存在大量不需要CPU的操作时(IO),适用于协程。

协程有极高的执行效率,因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销。

不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

因为协程是一个线程执行,所以想要利用多核CPU,最简单的方法是多进程+协程,这样既充分利用多核,又充分发挥协程的高效率。

那符合什么条件就能称之为协程:1、必须在只有一个单线程里实现并发 2、修改共享数据不需加锁 3、用户程序里自己保存多个控制流的上下文栈 4、一个协程遇到IO操作自动切换到其它协程

python中对于协程有两个模块,greenlet和gevent。

Greenlet

# Greenlet(greenlet的执行顺序需要我们手动控制)
from greenlet import greenlet
def test1():
    print (11)
    gr2.switch()    #手动切换
    print (22)
    gr2.switch()

def test2():
    print (33)
    gr1.switch()
    print (44)

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

gevent(自动切换,由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成)

from gevent import monkey; monkey.patch_all()
import gevent
import time

def foo():
    print(‘11‘)
    time.sleep(3)
    print(‘22‘)

def bar():
    print(‘33‘)
    print(‘44‘)

gevent.joinall([
    gevent.spawn(foo),
    gevent.spawn(bar),
])

GIL锁

1.什么是GIL?

GIL-全局解释器锁
GIL只在CPython解释器上存在,在Python的解释器中,使用的最多的是CPython解释器,所以不可避免的会遇到GIL

2.GIL对程序的影响

Pyhton的多线程是伪多线程,是并发的,因为无论如何都逃不过GIL解释器锁
因为GIL的存在,Python中同一时刻有且只有一个线程会执行,所以Python多线程无法利用多核CPU,所以Python的多线程不适合计算密集型的程序,只适合IO密集型

3.为什么多线程适合IO密集型程序?

通常程序分为两种,1.计算密集型程序 2.IO密集型程序
大部分的程序在运行时,都需要大量的IO操作,如网络数据的收发,大文件的读写
IO密集型程序在运行时,需要大量的时间进行等待,如果IO操作不完成,程序无法执行后面的操作,一直处于等待状态,导致CPU空闲.Python解释器在程序执行IO等待时,会释放GIL锁,让其他线程执行,提高Python程序的执行效率.

4.GIL的优缺点

优点:
    避免了大量的加锁解锁
    使数据更加安全,解决多线程间的数据完整性和状态同步
缺点:
    多核处理器退化成单核处理器,只能并发不能并行

5.如何改善GIL产生的问题

1.用多进程代替多线程
2.更换Python的解释器,如JPython,但其支持的模块少,用的人也少

6.有了GIl锁为什么还需要互斥锁

因为多个线程之间的GIL锁是自动获取和释放的,我们无法提前获知,所以需要自己加锁.

原文地址:https://www.cnblogs.com/abysschen/p/12527028.html

时间: 2024-10-09 03:01:10

进程/线程/协程/GIL的相关文章

# 进程/线程/协程 # IO:同步/异步/阻塞/非阻塞 # greenlet gevent # 事件驱动与异步IO # Select\Poll\Epoll异步IO 以及selectors模块 # Python队列/RabbitMQ队列

1 # 进程/线程/协程 2 # IO:同步/异步/阻塞/非阻塞 3 # greenlet gevent 4 # 事件驱动与异步IO 5 # Select\Poll\Epoll异步IO 以及selectors模块 6 # Python队列/RabbitMQ队列 7 8 ############################################################################################## 9 1.什么是进程?进程和程序之间有什么

初识进程 线程 协程(三):协程

协程:(又称微线程,也是交替运行) 进程-->线程-->协程 协程就是充分利用cpu给该线程的时间,多个协程只使用一个线程,某个任务遇到阻塞,执行下一个任务.如果一个线程只执行一个任务,比较容易进入阻塞队列,如果这条线程永远在工作(协程:一个线程执行多个任务),永远不会进入阻塞队列. 适用场景:    当程序中存在大量不需要CPU的操作时(IO) 特点: 每次都能从上次暂停的位置继续执行 三种实现方式: 1.yield(生成器) 生成器:一边计算一边循环的机制 def a(): ......

python的进程/线程/协程

1.python的多线程 多线程就是在同一时刻执行多个不同的程序,然而python中的多线程并不能真正的实现并行,这是由于cpython解释器中的GIL(全局解释器锁)捣的鬼,这把锁保证了同一时刻只有一个线程被执行. 多线程的特点: 线程比进程更轻量级,创建一个线程要比创建一个进程快10-100倍. 线程共享全局变量. 由于GIL的原因,当一个线程遇到IO操作时,会切换到另一个线程,所以线程适合IO密集型操作. 在多核cpu系统中,最大限度的利用多核,可以开启多个线程,开销比进程小的多,但是这并

进程线程协程那些事儿

一.进程与线程 1.进程 我们电脑的应用程序,都是进程,假设我们用的电脑是单核的,cpu同时只能执行一个进程.当程序出于I/O阻塞的时候,CPU如果和程序一起等待,那就太浪费了,cpu会去执行其他的程序,此时就涉及到切换,切换前要保存上一个程序运行的状态,才能恢复,所以就需要有个东西来记录这个东西,就可以引出进程的概念了. 进程就是一个程序在一个数据集上的一次动态执行过程.进程由程序,数据集,进程控制块三部分组成.程序用来描述进程哪些功能以及如何完成:数据集是程序执行过程中所使用的资源:进程控制

Python并发编程-进程 线程 协程

一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据集:数据集则是程序在执行过程中所需要使用的资源 3.进程控制块:进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感 知进程存在的唯一标志. 二.线程                                                                        

python 进程 线程 协程

并发与并行:并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔内发生.在单核CPU下的多线程其实都只是并发,不是并行. 进程是系统资源分配的最小单位,进程的出现是为了更好的利用CPU资源使到并发成为可能.进程由操作系统调度. 线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能.线程共享进程的大部分资源,并参与CPU的调度, 当然线程自己也是拥有自己的资源的,例如,栈,寄存器等等.线程由操作系统调度. 协程通

进程线程协程

一.进程 各个进程拥有自己的代码段. 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 二.线程 线程比进程轻量级,线程的切换cpu花费比进程小,线程能加大系统的并行度. 一个进程的各个线程之间是共享代码段的,各个线程都有一个程序计数器来指向下一条应该执行的指令. 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的). 三.协程 协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度.

进程,线程,协程的相关解释 《转载》

自己不太懂这一块,转发和大家一块分享!!! 进程,由OS来管理,每个进程都有自己独立的内存空间,进程之间通讯主要是通过信号传递的方式来实现的,实现方式有多种,信号量,管道,事件等,任何一种方式的通讯效率都需要过内核,导致通讯效率比较低.由于是独立的内存空间,所以上下文切换的时候需要保存当先调用栈的信息,cpu各寄存器的信息,虚拟内存,以及打开的相关句柄等信息,所以导致上下文切换的代价非常高,因此进程并不适合大量创建. 线程:也是由OS来管理的,一个进程可以拥有多个线程,但是其中每个线程会共享父进

进程线程协程的区别

一.概念 1.进程 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信.由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈.寄存器.虚拟内存.文件句柄等)比较大,但相对比较稳定安全. 2.线程 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存