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!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值