第十五章、并发编程之线程

目录

  • 第十五章、并发编程之线程

    • 1.什么是线程
    • 2. 进程和线程的区别
    • 3. 开启线程的两种方式
      • 函数开启
      • 类开启
    • 4.子线程与子进程创建速度
    • 5.子线程共享数据的证明
    • 6.线程的join方法
      • 单个子线程
      • 多个子线程
      • 思考
    • 7.了解进程的join
    • 8. 线程的其他相关用法

第十五章、并发编程之线程

1.什么是线程

纠正概念:进程其实不是个执行单位,进程是一个资源单位,每个进程内自带一个线程,线程才是cpu上的执行单位

抽象理解:

进程是指在系统中正在运行的一个应用程序;线程是系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元。对于操作系统而言,其调度单元是线程。

线程:cpu最小的执行单位
进程:资源集合/资源单位.
线程运行 = 运行代码
进程运行 = 各种资源 + 线程

图片理解:

例子理解:

在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
在工厂中,  每个车间都有房子,而且每个车间默认就有一条流水线.

2. 进程和线程的区别

  1. 线程:单个线程的内存空间数据共享(进程内的数据)
  2. 进程:物理内存空间隔离(多个进程内存空间彼此隔离)
  3. 进程是告诉操作系统开辟内存空间

    线程是告诉操作系统执行一条任务代码(线程的创建速度是进程的100倍)

3. 开启线程的两种方式

函数开启

from threading import Thread
import time
def task(name):
    print('%s is runing '%name)
    time.sleep(2)
    print('%s is done'%name)

t=Thread(target=task,args=('子线程',))
t.start()

类开启

class Task(Thread):
    def run(self):
    print('%s is runing ' % self.name)
    time.sleep(2)
    print('%s is done' % self.name)
t = Task()t.start()print('zhu')

4.子线程与子进程创建速度

from threading import Thread
from multiprocessing import Process
import time

def task(name):
    print(f'{name} is running')
    time.sleep(2)
    print(f'{name} is end')

if __name__ == '__main__':
    t = Thread(target=task,args=('子线程',))
    p = Process(target=task,args=('子进程',))
    # t.start()
    p.start()
    print('主')
------------------------------------------------
############开启子线程的打印效果:################

子线程 is running
主
子线程 is end

##########开启子进程打印效果:##################

主
子进程 is running
子进程 is end

总结:线程比进程创建速度快

5.子线程共享数据的证明

from threading  import Thread
import time,os

x = 100
def task():
    global x
    x = 50
    print(os.getpid()) # 4652

if __name__ == '__main__':

    t = Thread(target=task)
    t.start()
    time.sleep(2)
    print(x) # 50
    print(os.getpid()) # 4652
------------------------------------------
4652
50
4652

进程开启子进程是开辟新的内存空间,而线程开启子线程是共用一个内存空间

即:进程开启子进程的pid号不一样,

? 线程开启子线程的pid号一样

6.线程的join方法

单个子线程

子线程 start
主线程
子线程 endfrom threading import Thread
import time
def task():
    print('子线程 start')
    time.sleep(2)
    print('子线程 end')
def task2():
    print('子线程 start')
    time.sleep(5)
    print('子线程 end')

t = Thread(target=task)
t.start()
t2.start()
t.join() # 等待子线程运行结束
print('主线程')
-------------------------------
子线程 start
子线程 end
主线程
----------------------------------
#给t.join()加注释的结果如下
子线程 start
主线程
子线程 end

说明:主线程将会等待子线程的sleep和这样的一段时间,子线程的start()在join之前,说明该子线程必须运行结束,才运行到print(‘主线程‘),主线程才执行完毕,如果给t.join()加注释,则说明主线程执行完毕了后,主线程直接结束。

多个子线程

from threading import Thread
import time
def task(name,n):
    print(f'{name} start')
    time.sleep(n)
    print(f'{name} end')

t1 = Thread(target=task,args=('线程1',1))
t2 = Thread(target=task,args=('线程2',2))
t3 = Thread(target=task,args=('线程3',3))
start = time.time()
t1.start()
t2.start()
t3.start()
t1.join() # 111s
t2.join() #
t3.join()
end = time.time()
------------------------------------------
线程1 start
线程2 start
线程3 start
线程1 end
线程2 end
线程3 end
3.0022878646850586
#主线程开始->线程1开始->线程1结束->线程2开始->线程2结束->线程3开始->线程3结束->主线程结束
#因为1线程、2线程、3线程进入了同一个方法,本应该"同时"start()运行,但是现在是线程1 在start后使用join,那么线程2会老老实实的等线程1先跑完

说明:实现了多线程的并发执行

思考

? 思考一下 在单核的情况下 多个线程是如何利用cpu的?

? 答:单核CPU上运行的多线程程序, 同一时间只能一个线程在跑, 系统帮你切换线程而已, 系统给每个线程分配时间片来执行, 每个时间片大概10ms左右, 看起来像是同时跑, 但实际上是每个线程跑一点点就换到其它线程继续跑效率不会有提高的 切换线程反倒会增加开销

7.了解进程的join

from multiprocessing import Process
from threading import Thread
import time
def task():
    print('进程 开启')
    time.sleep(10)
    print('进程 结束')
def task2():
    print('子线程 开启')
    time.sleep(2)
    print('子线程 结束')

if __name__ == '__main__':
    p = Process(target=task)
    t = Thread(target=task2)
    t.start() # 开线程
    p.start() # 开进程
    print('子进程join开始')
    p.join() # 主进程的主线程等待子进程运行结束
    print('主') 

8. 线程的其他相关用法

   # print(t1.is_alive()) # True
   # print(t1.getName()) # Thread-1
   # print(t2.getName()) # Thread-2
   # t1.setName('班长')
   # print(t1.getName())
   # print(currentThread().name)
   # print(enumerate()) # [<_MainThread(MainThread, started 1856)>, <Thread(Thread-1, started 6948)>, <Thread(Thread-2, started 3128)>]
   # print(activeCount()) # 3
   # print(len(enumerate())) # 3

原文地址:https://www.cnblogs.com/demiao/p/11536044.html

时间: 2024-11-05 23:36:17

第十五章、并发编程之线程的相关文章

第十五章 并发编程

1.操作系统的发展史 参考:http://www.cnblogs.com/Eva-J/articles/8253521.html 知识点 输入输出 -- 大部分时间都不会占用CPU,但会降低你程序的效率 操作系统的三种基本类型:多道批处理系统.分时系统.实时系统. 现在操作系统 基于多道批处理系统和分时系统 多个程序.作业在遇到IO操作的时候,操作系统会帮助你进行切换 让CPU的利用率得到最大的提高 2.进程 初识进程 进程: 运行中的程序 操作系统 只负责管理调度进程 进程是操作系统中资源分配

[CSAPP笔记][第十二章并发编程]

第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟悉的例子. 我们主要将并发看做是一种操作系统内核用来运行多个应用程序的机制. 但是,并发不仅仅局限于内核.它也可以在应用程序中扮演重要的角色. 例如 Unix信号处理程序如何允许应用响应异步事件 例如:用户键入ctrl-c 程序访问虚拟存储器的一个未定义的区域 其他情况 访问慢速I/O设备 当一个应

第十二章 并发编程 学习笔记

第十二章 并发编程 进程是程序级并发,线程是函数级并发. 三种基本的构造并发程序的方法: 进程:每个逻辑控制流是个一个进程,由内核进行调度和维护. I/O多路复用:应用程序在一个进程的上下文中显式地调度他们自己的逻辑流. 线程:运行在单一进程上下文中的逻辑流,由内核进行调度. 12.1 基于进程的并发编程 构造并发程序最简单的方法就是用进程. 使用大家都很熟悉的函数例如: fork exec waitpid 关于在父.子进程间共享状态信息:共享文件表,但不共享用户地址空间. 进程又独立的地址空间

第十二章 并发编程

第十二章 并发编程 三种基本的构造并发程序 进程:每个逻辑控制流是一个进程,由内核进行调度,进程有独立的虚拟地址空间 I/O多路复用:逻辑流被模型化为状态机,所有流共享同一个地址空间 线程:运行在单一进程上下文中的逻辑流,由内核进行调度,共享同一个虚拟地址空间 常用函数: fork exec waitpid 基于I/O多路复用的并发事件驱动服务器 事件驱动程序:将逻辑流模型化为状态机. 状态机: 状态 输入事件 转移 对于状态机的理解,参考EDA课程中学习的状态转换图的画法和状态机. 整体的流程

“全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第三十五章:如何获取线程被等待的时间? 下一章 "全栈2019"Java多线程第三十六章:如何设置线程的等待截止时间 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复&qu

深入理解计算机系统 第十二章 并发编程

如果逻辑控制流在时间上重叠,那么它们就是并发的(concurrent) 这种常见的现象称为并发(concurrency),出现在计算机系统的许多不同层面上. 并发不仅仅局限于内核,它也可以在应用程序中扮演重要角色. 应用级并发在以下情况中都是很有用的: 1.访问慢速 I/O 设备 当一个应用正在等待来自慢速 I/O 设备(例如磁盘)的数据到达时,内核会运行其它进程,使 CPU 保持繁忙.每个应用都可以按照类似的方式,通过交替执行 I/O 请求和其他有用的工作来利用并发. 2.与人交互 和计算机交

深入理解计算机系统 第十二章 并发编程 (1)

现代操作系统提供了三种基本的构造并发程序的方法: 进程.用这种方法,每个逻辑控制流都是一个进程,由内核来调度和维护,因为进程有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信(interprocess communication,IPC)机制. I/O多路复用.在这种形式的并发编程中,应用程序在一个进程的上下文中显式的调度它们自己的逻辑流.逻辑流被模型化为状态机,数据到达文件描述符后,主程序显式的从一个状态转换到另一个状态.因为程序是一个单独的进程,所以所有的流都共享同一

深入理解计算机系统 第十二章 并发编程 part1 第二遍

三种构造并发程序的方法及其优缺点 1.进程 用这种方法,每个逻辑控制流都是一个进程,由内核来调度和维护.因为进程有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信机制. 优点: 由于进程有独立的地址空间,所以一个进程不可能不小心覆盖另一个进程的虚拟内存,这就消除了许多令人迷惑的错误 缺点: (1)还是由于进程有独立的地址空间,使得进程共享状态信息变得更加困难.为了共享信息,它们必须使用显式的 IPC(进程间通信)机制. (2)由于进程控制和 IPC 的开销很高,所以这种方

C++primer第十五章. 面向对象编程

面向对象编程基于三个基本概念:数据抽象.继承和动态绑定. 15.1. 面向对象编程:概述 面向对象编程的关键思想是多态性(polymorphism). 之所以称通过继承而相关联的类型为多态类型,是因为在许多情况下可以互换地使用派生类型或基类型的“许多形态”.正如我们将看到的,在 C++ 中,多态性仅用于通过继承而相关联的类型的引用或指针. 继承 派生类(derived class)能够继承基类(baseclass)定义的成员,派生类可以无须改变而使用那些与派生类型具体特性不相关的操作,派生类可以

Flask 学习笔记-第十五章-应用编程接口

(Rich Internet Application,RIA)的架构. 在RIA中,服务器的主要功能(有时是唯一功能)是为客户端提供数据存取服务. 在这种模式中,服务器变成了Web服务或应用编程接口(Application Programming Interface,API). 表现层状态转移(Representational State Transfer,REST)架构崭 露头角,成为Web程序的新宠,因为这种架构建立在大家熟识的万维网 基础之上. Web服务的REST架构方式,并列出了6个符