python线程和进程-未完待续
环境变量
https://blog.csdn.net/L_fengzifei/article/details/105156001
各脚本的父进程是pycharm,每次都会自动拷贝一份父进程的环境变量
0. 概念
- 多任务 程序
通过一个代码,同时执行多个事件
- 多任务 操作系统
一个操作系统可以执行多个程序
1. 并行/并发
https://zhuanlan.zhihu.com/p/362059793
多任务
理论上,一个CPU核心可以执行一个程序(独立的应用),多个程序就需要多个核心
一个核心通过快速执行多个任务(程序)来实现并发
假设是在 多核心单CPU 上讨论
多核CPU:多个核心处理器,处理器之间通过CPU内部总线进行通讯
下面所说的任务指的不是应用程序,一个应用程序可以产生多个任务
(当把应用程序说成任务的时候,任务可以产生多个子任务)
一个进程可以分为多个线程,并发/并行中讨论的任务指的是 线程???
并行、并发讨论的单位是线程
一般是操作系统控制CPU执行指令的
并行
同一时刻有多条指令在多个处理器(核心)上同时执行
同一时刻,执行多个任务(多个应用程序)
上述是进程并行
线程并行:一个时间段内每个线程分配给独立的核心,线程同时运行
多CPU中进程可以并行
单CPU多核心中线程可以并行
串行不是并发,串行仍然是一个时间点只能执行一个任务
串行:一个时间段内多个任务执行时一个任务执行完才能执行另一个
并行和串行是从执行者(cpu)角度观察
并发
https://mp.weixin.qq.com/s/G3Lnlm6cZiywCV8dfO2rng
同一时刻只有一个任务在执行
同一时间段内,多个任务(应用程序/进程)交替执行(包括启动、退出)
不同cpu实现并发的机制不同
单核单cpu,通过切换进程上下文实现并发( 每个进程运行在单个CPU上,如果单CPU有多个进程则多个进程并发执行)
多核单cpu,通过并行实现并发
上面是进程并发
线程并发:一个时间段多个线程在单个核心运行,统一时间只能一个线程运行
单CPU中进程只能并发
单CPU单核中线程只能并发
(??? 单CPU多核心 进程也只能并发???)
并发分类
- 并行并发
- 分时并发
高并发:单位时间内服务器处理很多请求 – ???
顺序执行相对于并发,上一个执行完,当前任务才执行
并发和顺序是从观察者(用户)角度观察
并行与并发的关系
并行和并发不是互斥的关系
并发关注任务的抽象调度
并行关注实际任务的执行
一个应用程序可以是多个任务(这里说的任务是程序中的事件)
一个应用程序可以是并发的,但不能是并行的:可以同时处理多个任务,但是没有两个任务可以同时执行
一个应用程序可以是并行的,但不能是并发的:同时处理多核CPU中一个任务的多个子任务
一个应用程序当即不能是并行的,也不能是并发的:顺序处理每个任务
一个应用程序可以并行的,可以是并发的:同时在多个CPU中同时处理多个任务
2.进程/线程
基本概念
https://zhuanlan.zhihu.com/p/362059793
操作系统可以执行多个任务,每个任务就是一个进程,进程可以同时执行多个子任务,每个子任务就是一个线程
(这里的说的 子任务 才对应的是 线程 中任务的概念)
操作系统
操作系统可以执行多个进程,每个进程可以执行多个线程
每个进程都有一个主线程
进程将资源分配给线程,一个进程内的线程之间共享进程的资源
进程
进程是系统进行资源分配和调度的基本单元,是操作系统结构的基础
是操作系统OS 进行资源(CPU、内存、磁盘、I/O)等分配的最小单元
通常一个程序就是一个进程,一个进程就是一个程序的运行实例
启动一个程序时,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,这样的环境称为进程*(感觉进程更像是一个上下文环境 )*
注意,一个进程可以拥有父进程和子进程,即进程拥有继承关系
线程
线程是进程的组成部分,一个进程可以有多个线程
线程:程序执行流的最小单元
是CPU调度和分配的基本单元(操作系用会根据进程的优先级和线程的优先级去调度CPU)
线程数:一种逻辑概念,是模拟出的CPU核心数
进程与线程的关系
进程可以简单理解为一个拥有自己独立的地址空间,一个进程可由多个线程的执行单元组成,每个线程都运行在同一进程的上下文中,共享进程该地址空间以及其内的代码和全局数据等资源,线程之间共享进程中的数据
每个进程至少有一个主线程,一般由系统自动创建,无需由用户创建。系统创建好进程后,实际上就是启动了执行该进程的主线程,(执行主线程以函数地址形式,即程序入口函数,将程序的启动点提供给操作系统),主执行线程终止或关闭,进程随之结束,操作系统回收该进程占用的资源
进程中任意线程执行出错,会导致进程的奔溃
进程之间的内容相互隔离,一个进程崩溃不会影响其他进程,如果进程之间需要进行数据的通信,需要使用用于进程间通信IPC的机制
对于内存,堆内存一般属于一个进程,但是栈(执行栈)却是属于一个线程的,且每个线程拥有一个独立的栈
程序运行后,会默认开启一个主进程,这个进程中会默认有一个主线程
进程 是资源+代码的统称
线程 是真正执行代码的
线程共享资源(共享进程的上下文),资源占用少,但是不稳定
进程不共享资源,复制资源,资源占用多,稳定
可以有
多进程并发/并行
多线程并发/并行
程序与进程/线程
程序:一组指令的有序集合,静态实体,没有任何运行的含义
进程:是程序在某个数据集上的执行,进程是程序的一次执行,是一个动态实体,有自己的生命周期,反映了一个程序在一定数据集上运行的全部动态过程
线程:程序执行的最小单元,每个程序都至少有一个线程,对于多线程的进程可以理解为一个进程同一时间段做多件事,每个线程可以处理不同的事务,一个线程阻塞不会影响另一个县城
线程
在多线程中,会有一个主线程来完成整个进程从开始到结束的全部操作,而其他线程会在主线程的运行中被创建或退出
当进程被初始化的时候,一个主进程就被创建了
当进程里只有一个线程的时候,叫单线程,多个线程叫多线程
# 程序运行就创建了一个主线程
import threading
def func():
pass
for x in range(10):
t=threading.Thread(target=func) # 创建一个线程,不是真的创建,测试therading.enumerate() 不显示该线程的信息
t.start() # 开启线程,这里才是真的创建
print(threading.enumerate()) # 查看线程信息,是一个list
threading.activate_count() # 当前活跃的线程数量
threading.current_thread() # 当前的线程的信息展示
- 每个线程必须有自己的 父进程
- 线程可以与(父进程 内的)其他线程,共享父进程 中的共享变量和部分环境,相互之间协同完成所有的任务
- 多个线程共享父进程的全部资源,但是要确保线程不会妨碍 同一进程 中的其他线程
线程是独立运行的,多线程是并发运行的,也就是同一时刻,主程序只允许一个线程执行
单核心CPU:无多线程*
多线程
https://blog.csdn.net/weixin_44917390/article/details/119610760
对于多线程的进程可以理解为一个进程同一时间段做多件事,每个线程可以处理不同的事务,一个线程阻塞不会影响另一个县城
多线程是实现异步的方法
多线程并行依赖于多核心,对应并行并发
多线程并发不依赖于多核心,对应分时并发
def func(param):
pass
t=threading.Thread(target=func,args=(param,)) # args 是一个元组 位置参数传递
t.start()
t=threading.Thread(target=func,kwargs=('key',value)) # kwargs 关键字参数传递
https://blog.csdn.net/qq_37193537/article/details/91043580
# 利用类创建线程
import threading
class CName(threading.Thread):
# 必须重写run
def run(self):
pass # code to be executed in class
instance=CName()
instance.start() # 自动调用run方法
class HandleData(threading.Thread):
def __init__(self,client_socket):
super().__init__()
self.client_socket=client_socket
def run(self):
while True:
recv_content=self.client_socket.recv(1024)
if len(recv_content):
self.client_socket.send(recv_content)
else:
self.client_socket.cloese()
break
class Server(threading.Thread):
def run(self):
server_s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_s.bind('ip',port)
server_s.listen(128)
while True:
new_s,client_info=server_s.accpet()
handle_data_thread=HandleData(new_s)
handle_data_thread.start() # 此时不会阻塞,而是继续等待监听、连接
server_s.close()
server=Server()
server.start()
队列
线程的执行结果,无法通过return进行返回,需要使用队列进行存储
队列是一个可变对象
# coding:utf-8
import threading
from queue import Queue
"""
Queue的使用
"""
def job(l, q):
for i in range(len(l)):
l[i] = l[i] ** 2
q.put(l)
def multithreading():
# 创建队列
q = Queue()
# 线程列表
threads = []
# 二维列表
data = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [6, 6, 6]]
for i in range(4):
t = threading.Thread(target=job, args=(data[i], q))
t.start()
threads.append(t)
# 对所有线程进行阻塞
for thread in threads:
thread.join()
results = []
# 将新队列中的每个元素挨个放到结果列表中
for _ in range(4):
results.append(q.get())
print(results)
if __name__ == "__main__":
multithreading()
互斥锁/线程共享
阻塞
t1=threading.Thread(target=func,args=(,))
t1.start() # 开启线程
t1.join() # 其他线程进行阻塞,在他之后的线程不能被执行
注意join 与 start 的顺序,与最终的执行结果,还有主线程
[https://blog.csdn.net/weixin_42277380/article/details/99670892]
https://blog.csdn.net/whatday/article/details/124308427
import threading
import time
def job(num):
print(f"{num} start \n")
time.sleep(1)
print(f"{num} finish \n")
def main():
added_thread=threading.Thread(target=job,name="T1",args=('1',))
added_thread2=threading.Thread(target=job,name="T2",args=('2',))
added_thread.start()
# added_thread2.start()
added_thread.join()
added_thread2.start()
added_thread2.join()
print("all done\n")
锁
g_num=0
def func1():
global g_num
g_num=10 # id 还是改变了
print(g_num)
def func2():
print(g_num) # 使用不使用线程都会接收到改变
t1=threading.Thread(target=func1)
t2=threading.Thread(target=func2)
t1.start()
sleep(2)
t2.start()
互斥锁 解决资源竞争问题
上锁到解锁之间的code 不允许被其他线程打扰,其他所有线程会阻塞
互斥锁已经上锁后,在该锁被解开之前,不能再被上锁
import threading
# 创建锁
mutex=threading.Lock()
# 上锁
mutex.acquire()
# 解锁
mutex.release()
mutex=threading.Lock()
g_num=0
def func1():
global g_num
mutex.acquire()
g_num=10 # id 还是改变了
# coding...
mutex.release()
print(g_num)
def func2():
print(g_num) # 使用不使用线程都会接收到改变
mutex.acquire()
# coding...
mutex.release()
t1=threading.Thread(target=func1)
t2=threading.Thread(target=func2)
t1.start()
sleep(2)
t2.start()
条件锁
进程
多进程
将整个程序划分为多个子任务(将一个进程分成多个线程(每个子任务对应一个线程)),这些任务在多核CPU上可以实现并行执行。在单个CPU上只能进行并发执行
程序自动创建一个主进程,其他就是子进程
进程之间不进行共享资源,即使是使用了全局变量,在一个进程中修改了全局变量,不会影响另一个进程的中的对应的变量
因此为了使用资源,那么就需要进行传参
这是因为,创建子进程时会复制父进程的内容
from multiprocessing import Process
def func():
pass
p1=Process(target=func,args=(,),kwargs={key:balue})
p.start()
多进程之间 queue 进行通信
from multiprocessing import Queue
3. 异步/同步/阻塞/非阻塞
https://mp.weixin.qq.com/s/G3Lnlm6cZiywCV8dfO2rng
https://blog.csdn.net/weixin_38256474/article/details/90347263
https://zhuanlan.zhihu.com/p/362059793
同步、异步关注的是消息通信机制
阻塞、非阻塞关注的是程序等待调用结果(消息、返回值)时的状态
个人理解:
同步/异步一般说的是发送方,也就是发送之后等不等待发送完成在返回
阻塞/非阻塞一般说的是接收方,也就是发送之后没有收到返回的数据就之等待或不等待
异步
异步指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有消息返回的时候会通知进程进行处理(发出请求后,该请求会在后台自动发出并获取数据,然后会数据进行处理,在此过程中,可以继续做其他操作,不管如何发出请求,也不关心如何处理数据)
同步
同步只是一个进程在执行某个请求的时候,如果该请求需要一段时间才能返回消息,那么这个进程会一直等待下去,直到收到返回消息才继续执行下去
阻塞
指调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果之后才会返回
非阻塞
指在不能立即得到结果之前,该调用不会阻塞当前线程
队列
传输二进制
https://blog.csdn.net/qq_37193537/article/details/91043580!!!