python-多任务编程
2. 多任务编程
2.1 多任务概述
-
多任务
即操作系统中可以同时运行多个任务。比如我们可以同时挂着qq,听音乐,同时上网浏览网页。这是我们看得到的任务,在系统中还有很多系统任务在执行,现在的操作系统基本都是多任务操作系统,具备运行多任务的能力。
-
计算机原理
-
CPU:计算机硬件的核心部件,用于对任务进行执行运算。
-
操作系统调用CPU执行任务
-
cpu轮询机制 : cpu都在多个任务之间快速的切换执行,切换速度在微秒级别,其实cpu同时只执行一个任务,但是因为切换太快了,从应用层看好像所有任务同时在执行。
-
多核CPU:现在的计算机一般都是多核CPU,比如四核,八核,我们可以理解为由多个单核CPU的集合。这时候在执行任务时就有了选择,可以将多个任务分配给某一个cpu核心,也可以将多个任务分配给多个cpu核心,操作系统会自动根据任务的复杂程度选择最优的分配方案。
- 并发 : 多个任务如果被分配给了一个cpu内核,那么这多个任务之间就是并发关系,并发关系的多个任务之间并不是真正的"同时"。
- 并行 : 多个任务如果被分配给了不同的cpu内核,那么这多个任务之间执行时就是并行关系,并行关系的多个任务时真正的“同时”执行。
-
-
什么是多任务编程
多任务编程即一个程序中编写多个任务,在程序运行时让这多个任务一起运行,而不是一个一个的顺次执行。
比如微信视频聊天,这时候在微信运行过程中既用到了视频任务也用到了音频任务,甚至同时还能发消息。这就是典型的多任务。而实际的开发过程中这样的情况比比皆是。
- 实现多任务编程的方法 : 多进程编程,多线程编程
-
多任务意义
-
提高了任务之间的配合,可以根据运行情况进行任务创建。
比如: 你也不知道用户在微信使用中是否会进行视频聊天,总不能提前启动起来吧,这是需要根据用户的行为启动新任务。
-
充分利用计算机资源,提高了任务的执行效率。
- 在任务中无阻塞时只有并行状态才能提高效率
- 在任务中有阻塞时并行并发都能提高效率
-
2.2 进程(Process)
2.2.1 进程概述
-
定义: 程序在计算机中的一次执行过程。
-
程序是一个可执行的文件,是静态的占有磁盘。
-
进程是一个动态的过程描述,占有计算机运行资源,有一定的生命周期。
-
-
进程状态
-
三态
就绪态 : 进程具备执行条件,等待系统调度分配cpu资源运行态 : 进程占有cpu正在运行 等待态 : 进程阻塞等待,此时会让出cpu
-
五态 (在三态基础上增加新建和终止)
新建 : 创建一个进程,获取资源的过程
终止 : 进程结束,释放资源的过程
-
-
进程命令
-
查看进程信息
ps -aux
- USER : 进程的创建者
- PID : 操作系统分配给进程的编号,大于0的整数,系统中每个进程的PID都不重复。PID也是重要的区分进程的标志。
- %CPU,%MEM : 占有的CPU和内存
- STAT : 进程状态信息,S I 表示阻塞状态 ,R 表示就绪状态或者运行状态
- START : 进程启动时间
- COMMAND : 通过什么程序启动的进程
-
进程树形结构
pstree
- 父子进程:在Linux操作系统中,进程形成树形关系,任务上一级进程是下一级的父进程,下一级进程是上一级的子进程。
-
2.2.2 多进程编程
-
使用模块 : multiprocessing
-
创建流程
【1】 将需要新进程执行的事件封装为函数
【2】 通过模块的Process类创建进程对象,关联函数
【3】 通过进程对象调用start启动进程
-
主要类和函数使用
Process()功能 : 创建进程对象参数 : target 绑定要执行的目标函数 args 元组,用于给target函数位置传参kwargs 字典,给target函数键值传参daemon bool值,让子进程随父进程退出
p.start()功能 : 启动进程
注意 : 启动进程此时target绑定函数开始执行,该函数作为新进程执行内容,此时进程真正被创建
p.join([timeout])功能:阻塞等待子进程退出参数:最长等待时间
进程创建示例:
"""
进程创建示例 01
"""
import multiprocessing as mp
from time import sleepa = 1 # 全局变量# 进程目标函数
def fun():print("开始运行一个进程")sleep(4) # 模拟事件执行事件global aprint("a =",a) # Yesa = 10000print("进程执行结束")# 实例化进程对象
process = mp.Process(target=fun)# 启动进程 进程产生 执行fun
process.start()print("我也做点事情")
sleep(3)
print("我也把事情做完了...")process.join() # 阻塞等待子进程结束
print("a:",a) # 1 10000
"""
进程创建示例02 : 含有参数的进程函数
"""
from multiprocessing import Process
from time import sleep# 含有参数的进程函数
def worker(sec,name):for i in range(3):sleep(sec)print("I'm %s"%name)print("I'm working....")# 元组位置传参
# p = Process(target=worker,args=(2,"Tom"))# 关键字传参
p = Process(target=worker,args = (2,),kwargs={"name":"Tom"},daemon=True) # 子进程伴随父进程结束
p.start()
sleep(3)
-
进程执行现象理解 (难点)
- 新的进程是原有进程的子进程,子进程复制父进程全部内存空间代码段,一个进程可以创建多个子进程。
- 子进程只执行指定的函数,其余内容均是父进程执行内容,但是子进程也拥有其他父进程资源。
- 各个进程在执行上互不影响,也没有先后顺序关系。
- 进程创建后,各个进程空间独立,相互没有影响。
- multiprocessing 创建的子进程中无法使用标准输入(即无法使用input)。
2.2.3 进程处理细节
- 进程相关函数
os.getpid()功能: 获取一个进程的PID值返回值: 返回当前进程的PID
os.getppid()功能: 获取父进程的PID号返回值: 返回父进程PID
sys.exit(info)功能:退出进程参数:字符串 表示退出时打印内容
"""
创建多个子进程
"""
from multiprocessing import Process
from time import sleep
import sys, osdef th1():sleep(3)print("吃饭")print(os.getppid(), "--", os.getpid())def th2():# sys.exit("不能睡觉了") # 进程结束sleep(1)print("睡觉")print(os.getppid(), "--", os.getpid())def th3():sleep(2)print("打豆豆")print(os.getppid(), "--", os.getpid())# 循环创建子进程
jobs = [] # 存放每个进程对象
for th in [th1, th2, th3]:p = Process(target=th)jobs.append(p) # 存入jobsp.start()# 确保三件事都结束
for i in jobs:i.join()
print("三件事完成")
随堂练习:大文件拆分
有一个大文件,将其拆分成上下两个部分 (按照字节大小),要求两个部分拆分要同步进行
plus : 假设文件很大不要一次read读取全部提示 : os.path.getsize() 获取文件大小创建两个子进程分别拆上下两个部分import os
from multiprocessing import Processfilename = "./dict.txt"
size = os.path.getsize(filename)# 如果父进程打开子进程直接用则会公用一个文件偏移量
# fr = open(filename,'rb')def top():fr = open(filename,'rb')fw = open('top.txt','wb')n = size // 2while n >= 1024:fw.write(fr.read(1024))n -= 1024else:fw.write(fr.read(n))fr.close()fw.close()def bot():fr = open(filename, 'rb')fw = open('bot.txt', 'wb')fr.seek(size//2,0) # 文件偏移量到中间while True:data = fr.read(1024)if not data:breakfw.write(data)fr.close()fw.close()jobs=[]
for item in [top,bot]:p = Process(target=item)jobs.append(p)p.start()[i.join() for i in jobs]
print("拆分完成")
-
孤儿进程和僵尸进程
-
孤儿进程: 父进程先于子进程退出时,子进程会成为孤儿进程,孤儿进程会被系统自动收养,成为孤儿进程新的父进程,并在孤儿进程退出时释放其资源。
-
僵尸进程: 子进程先于父进程退出,父进程又没有处理子进程的退出状态,此时子进程就会成为僵尸进程。
特点: 僵尸进程虽然结束,但是会存留部分进程资源在内存中,大量的僵尸进程会浪费系统资源。Python模块当中自动建立了僵尸处理机制,每次创建新进程都进行检查,将之前产生的僵尸处理掉,而且父进程退出前,僵尸也会被自动处理。
-
2.2.4 创建进程类
进程的基本创建方法将子进程执行的内容封装为函数。如果我们更热衷于面向对象的编程思想,也可以使用类来封装进程内容。
-
创建步骤
【1】 继承Process类
【2】 重写
__init__
方法添加自己的属性,使用super()加载父类属性【3】 重写run()方法
-
使用方法
【1】 实例化对象
【2】 调用start自动执行run方法
""" 自定义进程类 """ from multiprocessing import Process from time import sleepclass MyProcess(Process):def __init__(self, value):self.value = valuesuper().__init__() # 调用父类的init# 重写run 作为进程的执行内容def run(self):for i in range(self.value):sleep(2)print("自定义进程类。。。。")p = MyProcess(3) p.start() # 将 run方法作为进程执行
随堂练习: 1. 求100000以内质数之和,并且计算这个求和过程的时间2. 将100000分成4份,创建4个进程,每个进程求其中一份的 质数之和,统计4个进程执行完的时间提示: 质数: 只能被1和其本身整除的整数 >1 import time time.time()import time from multiprocessing import Process# 求begin -- end 之间的质数之和 class Prime(Process):@staticmethoddef is_prime(n):if n <= 1:return Falsefor i in range(2, n // 2 + 1):if n % i == 0:return Falsereturn Truedef __init__(self,begin,end):self.begin = begin # 起始数字self.end = end # 结尾数字super().__init__()def run(self):prime = [] # 存放所有质数for i in range(self.begin,self.end):if Prime.is_prime(i):prime.append(i) # 存入列表print(sum(prime))if __name__ == '__main__':# 4进程 用时: 9.434056282043457# 10进程 用时: 8.70681643486023jobs = []b = time.time()for i in range(1,100001,10000):p = Prime(i,i + 10000)jobs.append(p)p.start()[i.join() for i in jobs]print("用时:",time.time()-b)# def is_prime(n): # if n <= 1: # return False # for i in range(2,n // 2 + 1): # if n % i == 0: # return False # return True# def prime_sum(): # prime = [] # 存放所有质数 # for i in range(100001): # if is_prime(i): # prime.append(i) # 存入列表 # print(sum(prime))# 用时: 16.357502222061157 # begin = time.time() # prime_sum() # print("用时:",time.time()-begin)
2.2.5 进程间通信
-
必要性: 进程间空间独立,资源不共享,此时在需要进程间数据传输时就需要特定的手段进行数据通信。
-
常用进程间通信方法:消息队列,套接字等。
-
消息队列使用
- 通信原理: 在内存中开辟空间,建立队列模型,进程通过队列将消息存入,或者从队列取出完成进程间通信。
- 实现方法
from multiprocessing import Queueq = Queue(maxsize=0) 功能: 创建队列对象 参数:最多存放消息个数 返回值:队列对象q.put(data) 功能:向队列存入消息 参数:data 要存入的内容q.get() 功能:从队列取出消息 返回值: 返回获取到的内容q.full() 判断队列是否为满 q.empty() 判断队列是否为空 q.qsize() 获取队列中消息个数 q.close() 关闭队列
进程间通信示例:
from multiprocessing import Process,Queue# 创建消息队列
q = Queue(5)# 子进程函数
def handle():while True:cmd = q.get() # 取出指令if cmd == "1":print("\n完成指令1")elif cmd == "2":print("\n完成指令2")# 创建进程
p = Process(target=handle,daemon=True)
p.start()while True:cmd = input("指令:")if not cmd:breakq.put(cmd) # 通过队列给子进程
随堂练习:
有一个目录中有若干普通文件,将该目录复制一份到当前程序所在位置
要求: 目标文件夹中每个文件复制都采用一个独立的进程完成当所有文件复制完成之后,按复制完成顺序打印所有文件名
提示:
创建文件夹 : os.mkdir(dir) os.listdir()from multiprocessing import Process, Queue
import os# 消息队列
q = Queue()# 进程函数 复制文件
def copy(old,new,file):fr = open(old+'/'+file,'rb')fw = open(new+'/'+file,'wb')while True:data = fr.read()if not data:breakfw.write(data)fr.close()fw.close()q.put(file) # 存入队列# 入口函数
def main(old):new = old.split('/')[-1]os.mkdir(new) # 创建新文件夹jobs = [] # 存放每个进程对象# 循环创建进程 file --> 文件名称for file in os.listdir(old):p = Process(target=copy,args=(old,new,file))jobs.append(p)p.start()[i.join() for i in jobs] # 判断所有进程结束print("拷贝了如下文件:")while q.qsize():print(q.get())if __name__ == '__main__':main("/home/tarena/FTP")
**群聊聊天室 **
功能 : 类似qq群功能
【1】 有人进入聊天室需要输入姓名,姓名不能重复
【2】 有人进入聊天室时,其他人会收到通知:Lucy 进入了聊天室
【3】 一个人发消息,其他人会收到: Lucy : 一起出去玩啊。
【4】 有人退出聊天室,则其他人也会收到通知 : Lucy 退出了聊天室
【5】 扩展功能:服务器可以向所有用户发送公告: 管理员消息: 大家好,欢迎进入聊天室。
################ 服务端参考代码 ###################
from socket import *
from multiprocessing import Process# 服务器地址
HOST = "0.0.0.0"
PORT = 8888
ADDR = (HOST, PORT)# 存储用户信息 {name:address}
user = {}# 处理进入聊天室
def login(sock, name, address):if name in user or "管理" in name:sock.sendto(b"FAIL", address)else:sock.sendto(b"OK", address)# 告知其他人msg = "欢迎 %s 进入聊天室" % namefor key, value in user.items():sock.sendto(msg.encode(), value)user[name] = address # 存储用户# print(user) # 测试# 处理聊天
def chat(sock, name, content):msg = "%s : %s" % (name, content)for key, value in user.items():# 不是本人就发送if key != name:sock.sendto(msg.encode(), value)# 处理退出
def exit(sock, name):if name in user:del user[name] # 删除该用户# 通知其他用户msg = "%s 退出聊天室" % namefor key, value in user.items():sock.sendto(msg.encode(), value)def handle(sock):# 不断接收请求,分情况讨论while True:request, addr = sock.recvfrom(1024)tmp = request.decode().split(" ", 2)# 分情况讨论if tmp[0] == "LOGIN":# tmp ->[LOGIN,name]login(sock, tmp[1], addr)elif tmp[0] == "CHAT":# tmp ->[CHAT,name,content]chat(sock, tmp[1], tmp[2])elif tmp[0] == "EXIT":# tmp ->[EXIT,name]exit(sock, tmp[1])# 程序入口函数
def main():# 创建udpsock = socket(AF_INET, SOCK_DGRAM)sock.bind(ADDR)# 接收请求,分类处理p = Process(target=handle, args=(sock,), daemon=True)p.start()while True:content = input("管理员消息:")if not content:breakmsg = "CHAT 管理员消息 " + content# 从父进程发送到子进程sock.sendto(msg.encode(), ADDR)if __name__ == '__main__':main()################## 客户端参考代码 ##################
from socket import *
from multiprocessing import Process
import sys# 服务器地址
SERVER_ADDR = ("XX.XX.XXX.XX", 8888)def login(sock):while True:name = input("请输入昵称:")# 组织请求msg = "LOGIN " + namesock.sendto(msg.encode(), SERVER_ADDR)result, addr = sock.recvfrom(1024)if result == b"OK":print("进入聊天室")return nameelse:print("该昵称已存在")# 子进程接收函数
def recv_msg(sock):while True:data, addr = sock.recvfrom(1024 * 10)# 格式处理content = "\n" + data.decode() + "\n发言:"print(content, end="")# 父进程发送函数
def send_msg(sock, name):while True:try:content = input("发言:")except KeyboardInterrupt:content = "exit"# 表示退出if content == 'exit':msg = "EXIT " + namesock.sendto(msg.encode(), SERVER_ADDR)sys.exit("您已退出聊天室")msg = "CHAT %s %s" % (name, content)sock.sendto(msg.encode(), SERVER_ADDR)def main():sock = socket(AF_INET, SOCK_DGRAM)sock.bind(("0.0.0.0",55224)) # 端口不要变name = login(sock) # 请求进入聊天室# 子进程负责接收p = Process(target=recv_msg, args=(sock,), daemon=True)p.start()send_msg(sock, name) # 发送消息if __name__ == '__main__':main()
2.3 线程 (Thread)
2.3.1 线程概述
-
什么是线程
【1】 线程被称为轻量级的进程,也是多任务编程方式
【2】 也可以利用计算机的多cpu资源
【3】 线程可以理解为进程中再开辟的分支任务
-
线程特征
【1】 一个进程中可以包含多个线程
【2】 线程也是一个运行行为,消耗计算机资源
【3】 一个进程中的所有线程共享这个进程的资源
【4】 多个线程之间的运行同样互不影响各自运行
【5】 线程的创建和销毁消耗资源远小于进程
2.3.2 多线程编程
- 线程模块: threading
-
创建方法
【1】 创建线程对象
from threading import Thread t = Thread()
功能:创建线程对象
参数:target 绑定线程函数args 元组 给线程函数位置传参kwargs 字典 给线程函数键值传参daemon bool值,主线程推出时该分支线程也推出
【2】 启动线程
t.start()
【3】等待分支线程结束
t.join([timeout])
功能:阻塞等待分支线程退出
参数:最长等待时间
线程示例01:import threading
from time import sleep
import osa = 1# 线程函数
def music():global aprint("a =",a)a = 10000for i in range(3):sleep(2)print(os.getpid(),"播放:黄河大合唱")# 实例化线程对象
thread = threading.Thread(target=music)
# 启动线程 线程存在
thread.start()for i in range(4):sleep(1)print(os.getpid(),"播放:葫芦娃")# 阻塞等待分支线程结束
thread.join()
print("a:",a)
线程示例02:from threading import Thread
from time import sleep# 带有参数的线程函数
def func(sec,name):print("含有参数的线程来喽")sleep(sec)print("%s 线程执行完毕"%name)# 循环创建线程
for i in range(5):t = Thread(target=func,args=(2,),kwargs={"name":"T-%d"%i},daemon=True)t.start()
2.3.3 创建线程类
-
创建步骤
【1】 继承Thread类
【2】 重写
__init__
方法添加自己的属性,使用super()加载父类属性【3】 重写run()方法
-
使用方法
【1】 实例化对象
【2】 调用start自动执行run方法
from threading import Thread from time import sleepclass MyThread(Thread):def __init__(self,song):self.song = songsuper().__init__() # 得到父类内容# 线程要做的事情def run(self):for i in range(3):sleep(2)print("播放:",self.song)t = MyThread("凉凉") t.start() # 运行run
随堂练习: 现在有500张票,存在一个列表中 ["T1",...."T500"],10个窗口同时卖这500张票 W1-W10使用10个线程模拟这10个窗口,同时卖票,直到所有的票都卖出为止,每出一张票 需要0.1秒,打印表示即可print("W1----T250")from threading import Thread,Lock from time import sleeplock = Lock() # 创建锁# 将票准备好 ticket = ["T%d" % x for x in range(1, 501)]# 线程函数 w:表示窗口 def sell(w):while ticket:print("%s --- %s"%(w,ticket.pop(0)))sleep(0.1)# 10个线程 for i in range(1,11):t = Thread(target=sell,args=("W%d"%i,))t.start()
2.3.4 线程同步互斥
-
线程通信方法: 线程间使用全局变量进行通信
-
共享资源争夺
- 共享资源:多线程都可以操作的资源称为共享资源。对共享资源的操作代码段称为临界区。
- 影响 : 对共享资源的无序操作可能会带来数据的混乱,或者操作错误。此时往往需要同步互斥机制协调操作顺序。
-
同步互斥机制
-
同步 : 同步是一种协作关系,为完成操作,线程间形成一种协调,按照必要的步骤有序执行操作。
-
互斥 : 互斥是一种制约关系,当一个进程或者线程占有资源时会进行加锁处理,此时其他进程线程就无法操作该资源,直到解锁后才能操作。
-
- 线程Event
from threading import Evente = Event() 创建线程event对象e.wait([timeout]) 阻塞等待e被sete.set() 设置e,使wait结束阻塞e.clear() 使e回到未被设置状态e.is_set() 查看当前e是否被设置
Event使用示例:from threading import Thread, Eventmsg = None # 通信变量
e = Event() # 事件对象def 杨子荣():print("杨子荣前来拜山头")global msgmsg = "天王盖地虎"e.set() # 通知主线程可以判断t = Thread(target=杨子荣)
t.start()print("说对口令才是自己人")
e.wait() # 阻塞等待通知
if msg == "天王盖地虎":print("宝塔镇河妖")print("确认过眼神你是对的人")
else:print("打死他.... 无情啊 哥哥....")
- 线程锁 Lock
from threading import Locklock = Lock() 创建锁对象
lock.acquire() 上锁 如果lock已经上锁再调用会阻塞
lock.release() 解锁
Lock使用示例:from threading import Thread, Locklock = Lock() # 创建锁
a = b = 0def value():while True:lock.acquire() # 上锁if a != b:print("a = %d,b = %d" % (a, b))lock.release() # 解锁t = Thread(target=value)
t.start()while True:lock.acquire()a += 1b += 1lock.release()
随堂练习:
使用两个分支线程,一个线程打印1-52 这52个数字,另一个线程打印A-Z 这26个字母。要求同时执行两个线程,打印顺序为: 12A34B....5152Zfrom threading import Thread,Locklock1 = Lock()
lock2 = Lock()def print_num():for i in range(1,53,2):lock1.acquire()print(i)print(i + 1)lock2.release()def print_chr():for i in range(65,91):lock2.acquire()print(chr(i))lock1.release()t1 = Thread(target=print_num)
t2 = Thread(target=print_chr)lock2.acquire() # 先把打印字母的部分锁住t1.start()
t2.start()
2.3.5 死锁
-
什么是死锁
死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。
-
死锁产生条件
-
互斥条件:指线程使用了互斥方法,使用一个资源时其他线程无法使用。
-
请求和保持条件:指线程已经保持至少一个资源,但又提出了新的资源请求,在获取到新的资源前不会释放自己保持的资源。
-
不剥夺条件:不会受到线程外部的干扰,如系统强制终止线程等。
-
环路等待条件:指在发生死锁时,必然存在一个线程——资源的环形链,如 T0正在等待一个T1占用的资源;T1正在等待T2占用的资源,……,Tn正在等待已被T0占用的资源。
-
-
如何避免死锁
- 逻辑清晰,不要同时出现上述死锁产生的四个条件
- 通过测试工程师进行死锁检测
死锁现象演示:"""
死锁现象演示
"""
from time import sleep
from threading import Thread,Lock# 账户类
class Account:def __init__(self,id,balance,lock):self._id = idself._balance = balanceself.lock = lock# 取钱def withdraw(self,amount):self._balance -= amount# 存钱def deposit(self,amount):self._balance += amount# 查看余额def getBalance(self):return self._balance# 转账函数
def transfer(from_,to,amount):from_.lock.acquire()from_.withdraw(amount) # from_钱减少from_.lock.release() # 不会产生死锁sleep(0.1) # 网络延迟to.lock.acquire()to.deposit(amount) # to钱增加# from_.lock.release() # 产生死锁to.lock.release()if __name__ == '__main__':tom = Account("Tom",5000,Lock())abby = Account("abby",8000,Lock())t1 = Thread(target=transfer,args=(tom,abby,2000))t2 = Thread(target=transfer,args=(abby,tom,3000))t1.start()t2.start()t1.join()t2.join()print("Tom:",tom.getBalance())print("Abby:",abby.getBalance())
2.3.6 GIL问题
-
什么是GIL问题 (全局解释器锁)
由于python解释器设计中加入了解释器锁,导致python解释器同一时刻只能解释执行一个线程,大大降低了线程的执行效率。
-
导致后果
因为遇到阻塞时线程会主动让出解释器,去解释其他线程。所以python多线程在执行多阻塞任务时可以提升程序效率,其他情况并不能对效率有所提升。 -
关于GIL问题的处理
-
尽量使用进程完成无阻塞的并发行为
-
不使用c作为解释器 (可以用Java C#)
Guido的声明:http://www.artima.com/forums/flat.jsp?forum=106&thread=214235
-
-
结论
- GIL问题与Python语言本身并没什么关系,属于解释器设计的历史问题。
- 在无阻塞状态下,多线程程序程序执行效率并不高,甚至还不如单线程效率。
- Python多线程只适用于执行有阻塞延迟的任务情形。
线程效率对比进程实验:class Prime(Thread):# 判断一个数是否为质数@staticmethoddef is_prime(n):if n <= 1:return Falsefor i in range(2,n // 2 + 1):if n % i == 0:return Falsereturn Truedef __init__(self,begin,end):self.__begin = beginself.__end = endsuper().__init__()def run(self):prime = [] # 存放所有质数for i in range(self.__begin,self.__end):if Prime.is_prime(i):prime.append(i)print(sum(prime))@timeis
def process_10():jobs = []for i in range(1,100001,10000):t = Prime(i,i + 10000)jobs.append(t)t.start()for i in jobs:i.join()if __name__ == '__main__':process_10()
2.3.7 进程线程的区别联系
- 区别联系
- 两者都是多任务编程方式,都能使用计算机多核资源
- 进程的创建删除消耗的计算机资源比线程多
- 进程空间独立,数据互不干扰,有专门通信方法;线程使用全局变量通信
- 一个进程可以有多个分支线程,两者有包含关系
- 多个线程共享进程资源,在共享资源操作时往往需要同步互斥处理
- Python线程存在GIL问题,但是进程没有。
-
使用场景
- 任务场景:一个大型服务,往往包含多个独立的任务模块,每个任务模块又有多个小独立任务构成,此时整个项目可能有多个进程,每个进程又有多个线程。
- 编程语言:Java,C#之类的编程语言在执行多任务时一般都是用线程完成,因为线程资源消耗少;而Python由于GIL问题往往使用多进程。
相关文章:
![](https://i-blog.csdnimg.cn/direct/3f8db604d2b94bff8aedda46a71fea3d.png)
python-多任务编程
2. 多任务编程 2.1 多任务概述 多任务 即操作系统中可以同时运行多个任务。比如我们可以同时挂着qq,听音乐,同时上网浏览网页。这是我们看得到的任务,在系统中还有很多系统任务在执行,现在的操作系统基本都是多任务操作系统,具备…...
![](https://i-blog.csdnimg.cn/direct/e617d1a0156d42109741d38a1dc5f049.png)
IDEA创建Java工程、Maven安装与建立工程、Web工程、Tomcat配置
《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试(Debug) 第七章 …...
![](https://www.ngui.cc/images/no-images.jpg)
使用工作流产生高质量翻译内容的实战教程
大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…...
![](https://i-blog.csdnimg.cn/direct/7ce014d36210435eacd8798482a8cfc5.png)
笔记:Few-Shot Learning小样本分类问题 + 孪生网络 + 预训练与微调
内容摘自王老师的B站视频,大家还是尽量去看视频,老师讲的特别好,不到一小时的时间就缕清了小样本学习的基础知识点~Few-Shot Learning (1/3): 基本概念_哔哩哔哩_bilibili Few-Shot Learning(小样本分类) 假设现在每类…...
![](https://www.ngui.cc/images/no-images.jpg)
初学Mybatis之 CRUD 增删改查
namespace 中的包名要和 Dao/Mapper 接口的包名一致 select:选择,查询语句 同理,还有 insert、update、delete 标签 id:对应的 namespace 中的方法名 resultType:sql 语句执行的返回值 parameterType:…...
![](https://www.ngui.cc/images/no-images.jpg)
Kali Linux APT 设置指南:如何控制软件包更新行为
在我浏览 CSDN 的问答社区时,我发现一篇求助内容是一位用户对于如何在使用 APT 更新时避免更新 Arduino 这个问题感到困惑。这激发了我写这篇博客的灵感。我希望通过这篇文章,帮助那些在 Kali Linux 上使用 APT 管理软件包更新的朋友们,特别是…...
![](https://www.ngui.cc/images/no-images.jpg)
Android 10.0 Settings 加载流程
一、系统设置首页 代码路径:packages/app/Settings/ 1 主界面加载: <!-- Alias for launcher activity only, as this belongs to each profile. --><activity-alias android:name"Settings"android:label"string/settings_la…...
![](https://i-blog.csdnimg.cn/direct/6b9f8116b17a4068999f468cca10a11d.png)
mysql的索引、事务和存储引擎
目录 索引 索引的概念 索引的作用 作用 索引的副作用 创建索引 创建索引的原则和依据 索引的类型 创建索引 查看索引 删除索引 drop 主键索引 普通索引 添加普通索引 唯一索引 添加唯一索引 组合索引 添加组合索引 查询组合索引 全文索引 添加全文索引 …...
![](https://www.ngui.cc/images/no-images.jpg)
基于trace_id实现SpringCloudGateway网关的链路追踪
之前写的两篇关于基于 trace_id 的链路追踪的文章: 基于trace_id的链路追踪(含Feign、Hystrix、线程池等场景)基于trace_id的链路追踪(ForkJoinPool场景) 一、引言 在之前的文章中,我们讨论了基于 trace…...
![](https://www.ngui.cc/images/no-images.jpg)
Windows 11 version 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jul 2024)
Windows 11 version 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jul 2024) Windows 11, version 22H2,企业版 arm64 x64 请访问原文链接:https://sysin.org/blog/windows-11/,查看最新版。原创作品,转载请保留出处。 作者…...
![](https://i-blog.csdnimg.cn/direct/07775b7bde2f45f988a2650f4be1c691.png)
【C语言】动态内存管理(上)
文章目录 前言1.为什么要存在动态内存2. malloc和free2.1 malloc2.2 free2.3 使用实例(malloc和free) 3. calloc3.1 calloc例子 前言 本文开始将开始学习C语言中一个比较重要的知识点或者是操作——动态内存管理。由于本次的知识比较重要,为…...
![](https://img-blog.csdnimg.cn/direct/df413fc3bbea46f7962bc7fe31fa6a01.png)
【BUG】已解决:ModuleNotFoundError: No module named‘ pip‘
已解决:ModuleNotFoundError: No module named‘ pip‘ 目录 已解决:ModuleNotFoundError: No module named‘ pip‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰…...
![](https://www.ngui.cc/images/no-images.jpg)
网络安全-网络安全及其防护措施11
51.网络容量规划 网络容量规划的概念和重要性 网络容量规划: 是指根据业务需求和预期增长,合理规划和设计网络的带宽、设备和资源,以满足未来网络流量和服务质量的需求。通过有效的网络容量规划,确保网络性能稳定和用户体验良好…...
![](https://i-blog.csdnimg.cn/direct/f4e261a82f024069bd52482e3d468e02.png)
使用IDEA编写lua脚本并运行
下载lua https://github.com/rjpcomputing/luaforwindows/releases 是否创建桌面快捷方式:我们的目标是使用IDEA编写lua脚本,所以不需要勾选。后面需要的话,可以到安装目录下手动创建快捷方式 环境变量自动配置 安装后会自动配置好环境变量…...
![](https://i-blog.csdnimg.cn/direct/addbf989194241f6b801319ef1f5f0f9.png)
CentOS 7 安装MySQL 5.7.30
CentOS 7 安装MySQL卸载(离线安装) 安装配置MySQL之前先查询是否存在,如存在先卸载再安装 rpm -qa|grep -i mysql rpm -qa|grep -i mariadb rpm -e --nodeps mariadb-libs-5.5.68-1.el7.x86_64如下命令找到直接 rm -rf 删除(删除…...
![](https://img-blog.csdnimg.cn/fa80b15381a8400ca124d37ae57376ff.png)
Bash 学习摘录
文章目录 1、变量和参数的介绍(1)变量替换$(...) (2)特殊的变量类型export位置参数shift 2、引用(1)引用变量(2)转义 3、条件判断(1)条件测试结构(…...
![](https://i-blog.csdnimg.cn/direct/621cafe3056f49aa8155817bf79038f3.png)
GD32 MCU是如何进入中断函数的
用过GD32 MCU的小伙伴们都知道,程序是顺序执行的,但当有中断来的时候程序会跳转到中断函数,执行完中断函数后程序又继续回到原来的位置继续执行,那么你们知道MCU是如何找到中断函数入口的吗? 今天我们就以GD32F303系列…...
![](https://www.ngui.cc/images/no-images.jpg)
Ruby 循环
Ruby 循环 在编程中,循环是一种常用的控制结构,它允许我们重复执行一段代码多次。Ruby 作为一种灵活的编程语言,提供了多种循环方法,包括 while、until、for、each 和 loop 等。本文将详细介绍 Ruby 中的循环机制,并通…...
![](https://i-blog.csdnimg.cn/direct/2cae243d3c8f4b198bd1594165da8012.png)
三字棋游戏(C语言详细解释)
hello,小伙伴们大家好,算是失踪人口回归了哈,主要原因是期末考试完学校组织实训,做了俄罗斯方块,后续也会更新,不过今天先从简单的三字棋说起 话不多说,开始今天的内容 一、大体思路 我们都知…...
![](https://i-blog.csdnimg.cn/direct/21275bdb558e48bfb94b02929009515e.png)
H3CNE(计算机网络的概述)
1. 计算机网络的概述 1.1 计算机网络的三大基本功能 1. 资源共享 2. 分布式处理与负载均衡 3. 综合信息服务 1.2 计算机网络的三大基本类型 1.3 网络拓扑 定义: 网络设备连接排列的方式 网络拓扑的类型: 总线型拓扑: 所有的设备共享一…...
![](https://www.ngui.cc/images/no-images.jpg)
【极客日常】Golang一个的slice数据替换的bug排查
上周某天下班前,接到同事转来一个bug要排查,症状是代码重构之后某些业务效果不符合预期,由于代码重构人是笔者,于是blame到笔者这边。经过10min左右的排查和尝试后,解决了这个问题:既往逻辑没有改动&#x…...
![](https://i-blog.csdnimg.cn/direct/b261d216a196426788ebb3acbfda73ac.jpeg#pic_center)
HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 单选题序号3
基础认证题库请移步:HarmonyOS应用开发者基础认证题库 注:有读者反馈,题库的代码块比较多,打开文章时会卡死。所以笔者将题库拆分,单选题20个为一组,多选题10个为一组,题库目录如下,…...
![](https://i-blog.csdnimg.cn/direct/e3e4176119874666a41a7675ed24a518.png)
UE4-光照重建
当我们拉入新的光源和模型到我们的场景中后,会产生这样的情况: Preview:预览 表示此时由于光照物体所产生的阴影都是预览级别的并不是真正的效果。 方法一: 或者也可以在世界大纲中选中我们的光源,然后将我们的光源改变为可以…...
![](https://www.ngui.cc/images/no-images.jpg)
【2024德国签证】留学面签问题汇总
在去交材料的时候,可能会被随机安排面试。这些面试问题一般都很简单,主要是测试你的基本英文交流能力。无需担心,签证官不会问太专业的问题,因为他们也不懂专业内容。到目前为止,没有一个博士生因为这个面试被拒签。毕…...
![](https://img-blog.csdnimg.cn/201d4553cbce4376b2d0e55fab70c0a5.png)
知识点大纲
学习方法 学习、整理笔记过程中,顺便整理出一个以问题为模版的大纲,到时候对着问题,就像是在和面试官讲解那样,相当于升级版的费曼学习法 除了看博客,问gpt外,亲自实验也是获取知识及加深印象的关键点 很…...
![](https://i-blog.csdnimg.cn/direct/fdaa7086e030402688db881eb663c993.png)
MySQL:库表操作
MySQL:库表操作 库操作查看创建字符编码集 删除修改备份 表操作创建查看删除修改 库操作 查看 查看存在哪些数据库: show databases;示例: 查看自己当前处于哪一个数据库: select database();示例: 此处由于我不处于任…...
![](https://www.ngui.cc/images/no-images.jpg)
8.3 End-to-end Data Protection (Optional)
8.3 End-to-end Data Protection (Optional) 为了提供从应用程序到NVM介质并返回到应用程序本身的稳健数据保护,可以使用端到端数据保护。如果启用了此可选机制,则将额外的保护信息(例如CRC)添加到逻辑块中,控制器和/或主机软件可以对其进行评估,以确定逻辑块的完整性。…...
![](https://i-blog.csdnimg.cn/direct/320f738b8bd4471da2c38882db50f00c.png)
python实现图像对比度增强算法
python实现直方图均衡化、自适应直方图均衡化、连接组件标记算法 1.直方图均衡化算法详解算法步骤公式Python 实现详细解释优缺点 2.自适应直方图均衡化算法详解算法步骤公式Python 实现详细解释优缺点 3.连接组件标记算法详解算法步骤8连通与4连通公式Python 实现详细解释优缺…...
![](https://i-blog.csdnimg.cn/direct/eacf8c9a58a74a99b057b99e7c7bea04.png#pic_center)
【D3.js in Action 3 精译_020】2.6 用 D3 设置与修改元素样式 + 名人专访(Nadieh Bremer)+ 2.7 本章小结
当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介(已完结) 1.1 何为 D3.js?1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践(上)1.3 数据可视化最佳实践(下)1.4 本章小结 第二章…...
![](https://i-blog.csdnimg.cn/direct/6c57a0f7f55f4baa84083f523709f1e9.png)
GIT命令学习 二
📑打牌 : da pai ge的个人主页 🌤️个人专栏 : da pai ge的博客专栏 ☁️宝剑锋从磨砺出,梅花香自苦寒来 ☁️运维工程师的职责:监…...
![](/images/no-images.jpg)
四川住房和城乡建设厅网站打不开/外贸平台有哪些
导读: 一个用asp备份与恢复SQL Server数据库的例子代码,希望对一些朋友有用。(注意:数据库使用中可能无法恢复) SQL Server 数据库的备份与恢复 选择操作:备份 恢复 数据库名:"> 文件路径:(备份…...
![](/images/no-images.jpg)
开发公司工程部绩效考核管理办法/seo优化主要工作内容
【发包工具】http多线程发包工具 使用方法:输入地址,发送的内容,线程数,等待时间,每个线程发送的次数,GET/POST请求。 源代码 package com.xmxkkk.httptest; import java.awt.*; import java.awt.event.*; …...
![](https://img-blog.csdnimg.cn/img_convert/af8f0abae21ad36ff5db051ce35082cd.gif)
网站建设预算计算方法/百度seo关键词优化市场
👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇一年一度高考季和毕业季,填报志愿和大学生就业成为焦点问题。曾经面对清华70%~80%的高考状元都选择了金融行业,施一公呐喊:中国大学…...
![](/images/no-images.jpg)
传媒网站建设方案/品牌营销推广要怎么做
这篇的内容比较晦涩难懂。但是,它们是aaas的根。因为在紧接着要写的 (前面已经揭晓答案的)“aaas是什么“中需要提到。 整体上,aaas系统基于亚里士多德用来探究生命归属关系的三对区别distinctions的基础上给出对智能的三个方面a…...
![](https://img-blog.csdnimg.cn/img_convert/ff672262aaa3b1bae35901a76a9768af.png)
网站推广优化的公司/免费的推广引流软件
前言 Hi~,我是 2020 届物联网专业毕业生,现就读于杭州。谨以此文来记录我的秋招以及入门前端以来的学习历程,如有错误,希望大家能及时提出! 面试情况 前前后后一共面试了 14 家公司的前端岗,按城市划分为&…...
![](/images/no-images.jpg)
discuz做网站赚钱经历/网络推广和网站推广平台
首先搞明白mvvm是啥意思。vm是view mode的意思。所以mvvm框架是要有一个vm对象,来映射view。也就是vm对象的属性发生改变的时候,对应的视图部分会相对应更新。比较经典的有knockoutjs,里面比较关键的概念就是view model,compute&a…...