并发编程 --- 线程补充2

目录

  • 线程

线程

event事件

作用:用来控制线程的执行,

使用方法:

Event是threading中的一个类,调用里边的一些方法对线程进行一些操作。

e = Event()
在某一个线程中出现了e.wait()的时候,此时这个线程就不能执行,e.wait()可以在多个线程中。
接触e.wait()的方法是,在别的线程中使用e.set(),此时其他线程中的e.wait()的线程都可以继续运行。

例:
from threading import Event
from threading import Thread
import time
# 调用Event类实例化一个对象
e = Event()

# 若该方法出现在任务中,则为False,阻塞
# e.wait()  # False

# 若该方法出现在任务中,则将其他线程的Flase改为True,进入就绪态与运行态
# e.set()  # True

def light():
    print('红灯亮...')
    time.sleep(5)
    # 应该开始发送信号,告诉其他线程准备执行
    e.set()  # 将car中的False ---> True
    print('绿灯亮...')

def car(name):
    print('正在等红灯....')
    # 让所有汽车任务进入阻塞态
    e.wait()  # False
    print(f'{name}正在加速漂移....')

# 让一个light线程任务 控制多个car线程任务
t = Thread(target=light)
t.start()

for line in range(10):
    t = Thread(target=car, args=(f'童子军jason{line}号', ))
    t.start()

进程池与线程池

定义:线程池与进程池是用来控制当前程序允许进程/线程的数量。

问题:如果无限制的开启进程或线程,会将服务器卡崩。

作用:线程池与进程池的作用就是保证在硬件允许的范围内创建线程或进程的数量。

使用:

# 知识点一:(进程池与线程池的基本使用)
进程池:
from concurrent.futures import ProcessPoolExecutor

ProcessPoolExecutor(5)  # 5代表只能开启5个进程
ProcessPoolExecutor()   # 默认以CPU的个数限制进程数

线程池:
from concurrent.futures import ThreadPoolExecutor

ThreadPoolExecutor(5)  # 5代表只能开启5个进程
ThreadPoolExecutor()   # 默认以CPU个数 * 5限制线程数

# 知识点二:(利用进程池与线程池做的扩展)
pool.submit('传函数地址') # 异步提交任务
相当于下边的两步
t = Thread()
t.start()

# 会让所有线程池的任务结束后,才往下执行代码。
pool.shutdown()

# 知识点三:(回调函数:直接调用函数的返回值)
pool.submit(task, 1).add_done_callback(call_back)
被传函数的返回值,       将函数的返回值传给括号内的回调函数
注意:回调函数一定要写res.result(),因为不许通过res.result()才嫩刚拿到县城任务返回的结果。

# 例:
def task(res):
    print('线程任务开始了...')
    time.sleep(1)
    print('线程任务结束了...')
    return 123

# 回调函数
def call_back(res):
    print(type(res))
    # 注意: 赋值操作不要与接收的res同名
    res2 = res.result()
    print(res2)

for line in range(5):
    pool.submit(task, 1).add_done_callback(call_back)

print('hello')

协程

进程:资源单位

线程:执行单位

协程:为了在单线程下实现并发, 节约资源。

注意:协程不是操作系统的资源,他是程序起的名字,为了让单线程实现并发。

协程的目的:通过手动模拟操作系统 “多道技术” ,实现 切换 + 保存状态。为了让单个线程不停地切换去执行任务,让你第一个任务遇到IO操作了,会切换到另一个线程中进行操作,这样就可以使用一个线程就可以去完成之前需要几个线程才能完成的事情,但是在单线程计算密集行的情况下使用协程,这样做会让线程在计算任务之间来回切换,效率反而会更低。

协程的优点:在IO密集型的情况下,会提高效率

协程的缺点:在计算密集型的情况下,来回切换,反而效率会更低。

如何实现协程:切换 + 保存状态。

使用第三方模块:gevent

作用:可以帮助监听IO操作,并且切换。

使用gevent的目的:为了实现单线程下,实现遇到IO,实现 切换+保存状态。

from gevent import monkey
monkey.patch_all()  # 可以监听该程序下所有的IO操作
import time
from gevent import spawn, joinall  # 用于做切换 + 保存状态

def func1():
    print('1')
    # IO操作
    time.sleep(1)

def func2():
    print('2')
    time.sleep(3)

def func3():
    print('3')
    time.sleep(5)

start_time = time.time()

s1 = spawn(func1)
s2 = spawn(func2)
s3 = spawn(func3)

s2.join()  # 发送信号,相当于等待自己 (在单线程的情况下)
s1.join()
s3.join()
# 必须传序列类型
joinall([s1, s2, s3])

end_time = time.time()

print(end_time - start_time)

# 输出:
1
2
3
5.011829614639282

原文地址:https://www.cnblogs.com/whkzm/p/11735948.html

时间: 2024-10-17 08:00:09

并发编程 --- 线程补充2的相关文章

java并发编程线程安全

编写线程安全的代码实质就是管理对状态的访问,而且通常是共享的.可变的状态,对象的状态就是数据,存储在状态变量中,比如实例域,或者静态域,同时还包含了其它附属的域,例如hashmap的状态一部分存储到对象本身中,但同时也存储到很多mqp.entry中对象中,一个对象的状态还包含了任何会对他外部可见行为产生影响的数据. 所谓共享是指一个对象可以被多个线程访问, 所谓可变:是指变量的值在其生命周期内可以改变, 真正目的:在不可控制的并发访问中保护数据 线程安全必要条件: 1:对象是否被两个或以上的线程

17.并发编程--线程池

并发编程线程池 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要的等到线程创建就能立即执行. 第三:提高线程的可管理性.线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控.但是要做到合理的利用线程池,必须对其原理了如指掌. 1. Executor 框架简介 在 Java 5 之后,并发编程引入了一堆新的启动.调度和管理 线

JAVA 并发编程-线程同步工具类(十二)

本文主要介绍一些java线程同步工具类,并不进行具体讲解,当有需要时,可以再去结合实例学习. 信号灯(Semaphore) 应用场景举例: 例如公司的打卡系统,如果有一个打卡机,那么一次就只能有一个人打卡,其余的人就被阻塞住,打卡完以后就可由下一个人打卡.如果有3个打卡机,那么一次就允许3个人或者少于三个人打卡,其余的人就得等待打卡机空闲下来才能继续打卡. 结果: 已进入1个线程,还可进入2个 已进入2个线程,还可进入1个 已进入3个线程,还可进入0个 空余出1个 已进入4个线程,还可进入0个

JAVA 并发编程-线程同步通信技术(Lock和Condition)(十)

在之前的博客中已经介绍过线程同步通信技术<JAVA 并发编程-传统线程同步通信技术(四)>,上篇是使用的synchronized,wait,notify来实现,今天我们使用的是Lock和Condition,下面我们结合两者对比来学习. 简单的Lock锁应用: /** * 简单Lock的应用 * @author hejingyuan * */ public class LockTest { public static void main(String[] args) { new LockTest

Python并发编程-线程

Python作为一种解释型语言,由于使用了全局解释锁(GIL)的原因,其代码不能同时在多核CPU上并发的运行.这也导致在Python中使用多线程编程并不能实现并发,我们得使用其他的方法在Python中实现并发编程. 一.全局解释锁(GIL) Python中不能通过使用多线程实现并发编程主要是因为全局解释锁的机制,所以首先解释一下全局解释锁的概念. 首先,我们知道C++和Java是编译型语言,而Python则是一种解释型语言.对于Python程序来说,它是直接被输入到解释器中直接运行的.解释器在程

【python进阶】并发编程-线程与进程

并发编程-进程与线程 什么是进程(process)? 进程(process),是计算机中已运行程序的实体,是线程的容器:一个进程至少有一个线程 假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.是不是在程序A读取数据的过程中,让程序B去执行,当程序A读取完数据之后,让 程序B暂停,然后让程序A继续执行?当然没问题,但这里有一个关键词:切换既然是切换,那么这就涉及到了状态的保存

java之并发编程线程池的学习

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类. corePoolSize在很多地方被翻译成核心池大小,其实我的理解这个就是线程池的大小.举个简单的例子: 假如有一个工厂,工厂里面有10个工人,每个工人同时只能做一件任务. 因此只要当10个工人中有工人是空闲的,来了任务就分配给空闲的工人做:

Java并发编程——线程池的使用

在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPoolExecutor类中的方法讲起,

JAVA 并发编程-线程与进程的由来(一)

在学习Java编程之初,我们就接触过Java线程,当时敲过代码也总结过,但是现在看来还是有点缺陷,并没有联系线程的由来来说明问题,只是简单的介绍了什么是进程,什么是线程,以及它们之间的关系-<Java-线程>.今天我们从进程和线程的由来来补充一下之前的总结. 参考:http://www.cnblogs.com/dolphin0520/p/3910667.html 一.操作系统中为什么会出现进程? 说起进程的由来,我们需要从操作系统的发展历史谈起. 最初计算机: 也许在今天,我们无法想象在很多年