Python并发复习

一、多线程的调用

threading 模块建立在thread 模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装,

提供了更方便的api来处理线程。

多线程的调用有两种方式,函数式继承式

import threading
import time

def sayhi(num): #定义每个线程要运行的函数

    print("running on number:%s" %num)

    time.sleep(3)

if __name__ == ‘__main__‘:

    t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
    t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例

    t1.start() #启动线程
    t2.start() #启动另一个线程
import threading
import time

class MyThread(threading.Thread):
    def __init__(self,num):
        super().__init__
        self.num = num

    def run(self):#定义每个线程要运行的函数

        print("running on number:%s" %self.num)

        time.sleep(3)

if __name__ == ‘__main__‘:

    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()

二、 阻塞线程和守护线程

join():

  在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

setDaemon(True):

将线程声明为守护线程,必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起。这个方法基本和join是相反的。

当我们 在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成

想退出时,会检验子线程是否完成。如 果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程

完成了,不管子线程是否完成,都要和主线程一起退出,

 1 #!/usr/bin/env python
 2 # encoding: utf-8
 3
 4 """
 5 @version: python37
 6 @author: Geoffrey
 7 @file: 多线程复习.py
 8 @time: 18-10-27 上午9:48
 9 """
10
11 import threading
12 from time import ctime,sleep
13
14
15 def func(name, i):
16         print (f"开始第{i}个线程 --- {name} {ctime()}")
17         sleep(3)
18         print(f"停止 第{i}个线程 {ctime}")
19
20
21 threads = []
22
23 t0 = threading.Thread(target=func,args=(‘Julia‘,0))
24 t1 = threading.Thread(target=func,args=(‘Python‘,1))
25 t2 = threading.Thread(target=func,args=(‘C++‘,2))
26 t3 = threading.Thread(target=func,args=(‘Java‘,3))
27
28 threads.append(t0)
29 threads.append(t1)
30 threads.append(t2)
31 threads.append(t3)
32
33 if __name__ == ‘__main__‘:
34
35     for i,t in enumerate(threads):
36 37         t.setDaemon(bool(i))# 将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。
38         t.start()
39         # t.join() # 设置为阻塞线程
40
41     print (" --------- 主线程执行完成 %s" %ctime())

不设置守护线程,默认是非守护线程。

如果t1,t2,t3设置设置为守护线程,执行结果为在主线程执行完毕后,他们是否执行完成不能保证,随着主进程结束而结束。

如果设置全部为阻塞线程,结果为轮流执行,相当于单线程。

三、互斥锁,GIL

1、Cpython的GIL解释器锁的工作机制   

在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势。需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。Python同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。CPython是Python的一种,GIL不是Python语言的缺陷。所以明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL。

1.2 GIL的介绍

GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。要想了解GIL,首先确定一点:每次执行python程序,都会产生一个独立的进程。例如python test1.py,python test2.py,python test3.py会产生3个不同的python进程。

1.3 GIL原理   

第一点:
所有数据都是共享的,这其中,代码作为一种数据也是被所有线程共享的(test.py的所有代码以及Cpython解释器的所有代码)例如:test.py定义一个函数work(代码内容如下图),在进程内所有线程都能访问到work的代码,于是我们可以开启三个线程然后target都指向该代码,能访问到意味着就是可以执行。
第二点:
所有线程的任务,都需要将任务的代码当做参数传给解释器的代码去执行,即所有的线程要想运行自己的任务,首先需要解决的是能够访问到解释器的代码。
   
总结:

解释器的代码是所有线程共享的,所以垃圾回收线程也可能访问到解释器的代码而去执行,这就导致了一个问题:对于同一个数据100,可能线程1执行x=100的同时,而垃圾回收执行的是回收100的操作,解决这种问题没有什么高明的方法,就是加锁处理,即GIL,保证python解释器同一时间只能执行一个任务的代码。

1.4 GIL和Lock 

锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据。保护不同的数据就应该加不同的锁。所以,解释就是GIL 与Lock是两把锁,保护的数据不一样,前者是解释器级别的(当然保护的就是解释器级别的数据,比如垃圾回收的数据),后者是保护用户自己开发的应用程序的数据,很明显GIL不负责这件事,只能用户自定义加锁处理,即Lock。如下图:

1、100个线程去抢GIL锁,即抢执行权限
2、肯定有一个线程先抢到GIL(暂且称为线程1),然后开始执行,一旦执行就会拿到lock.acquire()
3、极有可能线程1还未运行完毕,就有另外一个线程2抢到GIL,然后开始运行,但线程2发现互斥锁lock还未被线程1释放,于是阻塞,被迫交出执行权限,即释放GIL
4、直到线程1重新抢到GIL,开始从上次暂停的位置继续执行,直到正常释放互斥锁lock,然后其他的线程再重复2 3 4的过程

原文地址:https://www.cnblogs.com/geoffreyone/p/9862790.html

时间: 2024-10-02 08:23:15

Python并发复习的相关文章

python并发编程之多进程

python并发编程之多进程 一.什么是进程 进程:正在进行的一个过程或者一个任务,执行任务的是CPU. 原理:单核加多道技术 二.进程与程序的区别 进程是指程序的运行过程 需要强调的是:同一个程序执行两次是两个进程,比如打开暴风影音,虽然都是同一个软件,但是一个可以播放苍井空,另一个可以播放武藤兰. 三.并发与并行 无论是并行还是并发,在用户看来都是'同时'运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务. (1)并发

python-学习-python并发编程之多进程与多线程

一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.Python提供了multiprocessing.    multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似.  multiprocessing模块的功能众多:支持子进程.通信和共享数据.执行不同形式的同步,

Python并发编程实例教程

有关Python中的并发编程实例,主要是对Threading模块的应用,文中自定义了一个Threading类库. 一.简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执行,这个控制流被称为该进程的主线程.在任何给定的时刻,一个程序只做一件事情. 一个程序可以通过Python库函数中的os或subprocess模块创建新进程(例如os.fork()或

python并发的痛——多线程

伴随着多核时代的到来,怎样充分利用好你的多个CPU的优势成了技术的关注点,那就是多线程多进程编程,二者的区别也很明显,进程是操作系统中拥有资源的最小单位,但是是重量级的.线程是系统调度的最小单位,是轻量级的,一个进程可以拥有很多个线程,但是线程是不拥有资源的,同一个进程中的线程共享这个进程中拥有的资源.以前学习java,一个灰常重要的并发方式就是多线程,因为线程的开销要比进程的少很多,而通过加锁来保证线程安全,进而有线程池来做进一步的优化. 所以前面也花了些时间对python的多线程编程进行了了

python并发编程&多线程(一)

本篇理论居多,实际操作见:  python并发编程&多线程(二) 一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线 流水线的工作需要电源,电源就相当于cpu 所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位. 多线程(即多个控制线程)的概念

python并发编程&多线程(二)

前导理论知识见:python并发编程&多线程(一) 一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性 官网链接:https://docs.python.org/3/library/threading.html?highlight=threading#(装B模式加载中…………) 二 开启线程的两种方式  方式一  方式二 三 在一个进程下开启多个线程与在一个进程下开启多个子进程的区别  1 谁的开启速度快  2 瞅

Python并发目录

Python并发目录 Python网络编程-IO阻塞与非阻塞及多路复用 Python进程-理论 Python进程-实现 Python进程间通信 注意点 python编程中的if __name__ == 'main与windows中使用多进程 综合运用实例 Python Socket请求网站获取数据  未完待续…… 原文地址:https://www.cnblogs.com/xiao-apple36/p/8684874.html

Python并发编程系列之多线程

1引言 2 创建线程 2.1 函数的方式创建线程 2.2 类的方式创建线程 3 Thread类的常用属性和方法 3.1 守护线程:Deamon 3.2 join()方法 4 线程间的同步机制 4.1 互斥锁:Lock 4.2 递归锁:RLock 4.3 Condition 4.4 信号量:Semaphore 4.5 事件:Event 4.6 定时器:Timer 5 线程间的通行 5.1队列:Queue 6 线程池 7 总结 1 引言 上一篇博文详细总结了Python进程的用法,这一篇博文来所以说

python 并发编程 多进程 目录

python multiprocessing模块 介绍 python 开启进程两种方法 python 并发编程 查看进程的id pid与父进程id ppid 原文地址:https://www.cnblogs.com/mingerlcm/p/11029215.html