线程与进程的关系

概念:

线程的进程的一部分

进程是正在运行的程序实体

一个进程包含多个线程 

进程是程序中的资源调度的一个最小单位:一个进程可以并发多个线程,多个线程做不同的任务

不同的进程之间资源不共享,但是一个进程中的多个线程资源完全共享

多线程会导致资源冲突: win一般采用 多线程

多进程会导致资源占用不足: Linux不支持多线程, 只采用重量级多进程

并发和并行:

并发:通过cpu的调度,让用户看上去同时执行,实际上cpu操作层面不是真正的同时(多线程同时操作

并行: 多个cpu实例或者多台机器同时执行

python 全局锁 GIL(Global Interpreter Lock)

因此:不管如何设置多线程,都是并发而不是并行

故此: python的多线程编程技术只适合IO密集型的任务, 不适合计算型(cpu应用多)的任务

IO密集型: 频繁的读写数据的场景叫 IO密集型的任务,如 增删改查

计算型   : 频繁调用cpu计算的场景,叫计算密集型的场景, 如 算法逻辑运算

 解决GIL的办法: 多进程的技术

python实现多线程的几种方式:

thread:模块提供了基本的线程和互斥锁的支持,更底层的实现模块

def start_new_thread (function, args, kwargs=None): 开启一个新的线程, 参数跟方法名字 ,元祖, 可选参数可以为空

threading: threading封装了thread,提供了更加全面的线程使用方法,是更高级的线程实现模块

Thread对象      描述

name      线程名

ident      线程标志

daemon     表示是否是守护线程

__init__(group=None, tatget=None,args= (), kwargs ={}, verbose=None, daemon=None)   实例化一个线程对象,需要有一个可 调用的 target

start()       开始执行该线程

run()      线程启动时,运行的函数,通常会被 重写

join (timeout=None)  阻塞,直到达到timeout或者其他线 程执行完毕

getName()      返回线程名 设置线程名 线程是否存活 判断是否是守护线程
setName (name) isAlivel /is_alive () isDaemon() setDaemon(daemonic)   把线程的守护标志设定为True或者 False (必须在线程 start()之前调 用)

原语:指不可分割的多个操作

锁源于对象,就是把线程执行任务过程中的多个指令变成不可以被分割的,从而锁定任务, 让其他线程无法访问。

 守护线程与非守护线程

守护线程:其他线程都运行结束后,守护线程立即结束

非守护线程:无论其他线程有没有运行结束,本线程都必须正常运行结束后才会结束。

通过  daemon去设置是否为守护线程

语法: Thread().daemon = True /false

线程阻塞

线程阻塞就是指,把当前运行的线程阻塞,让其停止运行,直到所有其他线程运行完毕后,再继续执行。

语法: Thread().join()

作用:阻塞主线程的运行,让主线程等待所有子线程运行结束之后,再继续运行 
应用场景:例如当所有子线程都是守护线程,而主线程很快就会结束时,

那么我们看可以使 用.join()方法,阻塞主线程的运行,让子线程运行完毕之后,再继续运行主线程。

线程锁(Lock)和信号量

线程锁(Lock): 为了防止线程与线程之间资源共享导致的线程安全问题,我们可以对访问的资源加上锁,这个锁就是线程锁。 

Lock对象语法

Lock是锁原语

原语: 一般是指由若干条指令组成的程序段,用来实现某个特定功能,在执行过程中不可被 中断。

Lock对象方法 描述 acquire() 获取锁 release() 释放锁

获取锁后,就可以把当前的资源锁定,其他线程只能等待锁释放后才能获取到该资源。

信号量:信号量是指控制有多少个线程可以访问的相同资源

语法:

semaphore=threading.Semaphore(3)#同一时间只能有3个线程处于运行状态

semaphore.acquire() 获取信号量,信号量减一

semaphore.release() 释放信号量,信号量加一

 队列

队列:一种数据结构

队列的类型:双向队列(deque)、先进先出队列 、后进先出队列、优先级队列等等

队列的特点:在python中,一切皆对象,所以任何东西都可以放入队列中,使用队列进行管 理。

如类、方法、变量等等。

队列的应用:亿级吞吐量消息队列Kafka;标准消息队列RabbitMq等等;线程池是基于队列 技术实现;

用法:

队列常见操作方法:

from queue import Queue #创建队列
q = Queue(maxsize=10)

Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
Queue.get_nowait() 相当Queue.get(False)
Queue.put(item) 写入队列,timeout等待时间
Queue.put_nowait(item) 相当Queue.put(item, False)
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列 发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作

线程池

 顾名思义就是存放线程的池子,线程池可以控制线程的启动数量,从而达到节省系统资源的 目的。

作用:可以控制要启动的线程数量。 线程池与信号量Semaphore的区别:

线程池控制的是线程数量,而信号量控制的是并发数量。

超过信号量规定数量的线程,已经被启动了,只是状态是挂起。而线程池中,超过了线程池规定数量的线程,还没有启动,只能等待启动。

Python实现线程池的两种方式:

1:concurrent.futures中的ThreadPoolExecutor

2:threadpool库

 关于threadpool的使用方式咯!!!

  安装threadpool库

1
pip install threadpool

  导包

1
from threadpool import ThreadPool, makeRequests

  创建线程池

1
pool = ThreadPool(10) # 能装下10个线程

 添加任务

1
requests = makeRequests(action, args, callback=None)

 执行任务

1
[pool.putRequest(req) for req in requests]

  等待执行

1
pool.wait()

tomorrow库 

 多线程库tomorrow是一个专门用来进行并发测试的库,我们使用tomorrow库,可以更容易地实现多线程运行程序

tomorrow是基于concurrent.futures中的ThreadPoolExecutor实现的库,它实现了一个并 发测试的装饰器,通过这个装饰器,我们可以简化代码,达到进行多线程并发测试的目的

 

1
2
3
4
5
6
7
from tomorrow import threads
import threading
@threads(10) # 最多开启10个线程完成任务 def task( task_name):
print( threading.current_thread().name +"正在:", task_name)
if __name__ == '__main__':
task_name_list = ["听歌", "吃饭", "聊天"] for i in range(3):
        task(task_name_list[i])

  

 

 

 

 

 

 

 

 

 

 

 

posted @   TheBlueaa  阅读(258)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示