2024年Python最新【python开发】并发编程(下),2024年最新字节跳动的面试流程

简介: 2024年Python最新【python开发】并发编程(下),2024年最新字节跳动的面试流程
也可以把多进程放在函数里,用main函数来运行。
from multiprocessing import Process
def task(arg):
pass
def run():
p = Process(target=task, args=(‘xxx’, ))
p.start()
if name == ‘__main__’:
run()
在python中基于multiprocessing模块操作的进程,start methods主要有三种:
1. fork:可以拷贝几乎所有资源,支持文件对象/线程锁等传参,unix系统适用,任意位置开始;
2. spwan:run参数必备资源,不支持文件对象/线程锁等传参,unix、win适用,main代码模块开始;
3. forkserver:run参数必备资源,不支持文件对象/线程锁等传参,部分unix适用,main代码模块开始。
### (二)案例
#### 1、示例一:fork模式下复制列表元素到子进程中
先创建一个子进程,然后设置模式为fork,我们可以运行一下子进程,看看线程里的name长什么样,实验结果显示,主线程的name被复制到子进程里。
import multiprocessing
def task():
print(name)
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
p1 = multiprocessing.Process(target=task)
p1.start()

#[]

在子进程里面修改name,增加列表元素,在子进程和主进程里分别打印name观察,可以发现:进程中改变的name并不会影响主进程中的name。
import multiprocessing
import time
def task():
print(name)
#[]
name.append(123)
print(name)
#[123]
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
p1 = multiprocessing.Process(target=task)
p1.start()
time.sleep(2)
print(name)
#[]
但是如果append操作放在主线程里,那么经过append操作的name会被复制到进程中,在子进程中打印name可以发现是多了123元素的列表。
import multiprocessing
import time
def task():
print(name)
#[123]
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
name.append(123)
p1 = multiprocessing.Process(target=task)
p1.start()
#### 2、示例二:spawn模式下复制列表元素到子进程中
切换到spawn模式后,我们可以发现在spawn模式下,name并不能直接复制到进程中,会报错,所以只能当作参数传入到task中。
import multiprocessing
import time
def task(data):
print(data)
#[]
if name == ‘__main__’:
multiprocessing.set_start_method(“spawn”) #fork、spawn、forkserver
name = []
p1 = multiprocessing.Process(target=task, args=(name, ))
p1.start()
同样的,在子进程中对name进行append操作,结果发现子进程中的改变并不会影响主进程中的name。
import multiprocessing
import time
def task(data):
print(data)
#[]
data.append(999)
print(data)
#[999]
if name == ‘__main__’:
multiprocessing.set_start_method(“spawn”) #fork、spawn、forkserver
name = []
p1 = multiprocessing.Process(target=task, args=(name, ))
p1.start()
time.sleep(2)
print(name)
#[]
#### 3、示例三:在fork模式下复制文件对象到子进程中
spawn并不支持特殊对象:文件或锁的传参,而且即使是普通对象也只能通过传参的形式进行传递。
import multiprocessing
import time
def task():
print(name)
#[]
file_object.write(‘闫曦月\n’)
file_object.flush() #高宇星和闫曦月这两个内容已经刷到硬盘中了
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
file_object = open(‘x1.txt’, mode=‘a+’, encoding=‘utf-8’)
file_object.write(‘高宇星\n’)
#写入到内存中,内容还没有写到文件里,在子进程运行完之后才会将该内容刷到硬盘上
p1 = multiprocessing.Process(target=task)
p1.start()
txt的内容是:  
 高宇星  
 闫曦月  
 高宇星
在本案例中,我们创建了一个txt文件,并将高宇星复制到子进程中,子进程在flush的时候把两个数据都写到了硬盘中,最后等子进程运行完之后,主进程再次将高宇星这条数据刷到硬盘中。
import multiprocessing
import time
def task():
print(name)
#[]
file_object.write(‘闫曦月\n’)
file_object.flush()
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
file_object = open(‘x1.txt’, mode=‘a+’, encoding=‘utf-8’)
file_object.write(‘高宇星\n’)
file_object.flush()
p1 = multiprocessing.Process(target=task)
p1.start()


txt的内容是:  
 高宇星  
 闫曦月
这里有不同点,是在主进程里,已经进行了flush,所以已经将内存中的信息高宇星刷到硬盘上了,所以在子进程运行结束之后就不会再刷高宇星到硬盘上了。
#### 4、示例四:在fork模式下复制锁到子进程中
spawn模式下,锁没有办法被传参。
import multiprocessing
import threading
def task():
print(file_object, lock)
#<_io.TextIOWrapper name=‘x1.txt’ mode=‘a+’ encoding=‘utf-8’> 
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
file_object = open(‘x1.txt’, mode=‘a+’, encoding=‘utf-8’)
lock = threading.RLock()
p1 = multiprocessing.Process(target=task)
p1.start()
当我们在主进程中申请了锁之后,主进程中打印出来的锁是已经进行locked过的。
import multiprocessing
import threading
def task():
pass
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
lock = threading.RLock()
print(lock)
#
lock.acquire()
print(lock)
# 
lock.release()
print(lock)
#
lock.acquire()
print(lock)
#
p1 = multiprocessing.Process(target=task)
p1.start()
当我们在主进程中申请了锁之后,子进程中打印出来的锁是已经进行locked过的,是子进程的主线程锁的。
import multiprocessing
import threading
def task():
#拷贝的锁也是申请走的状态,被谁申请走了?被子进程中的主线程申请走了
print(lock)
#
lock.acquire()
print(666)
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
lock = threading.RLock()
#
lock.acquire()
p1 = multiprocessing.Process(target=task)
p1.start()
锁被子进程中的主线程申请走了,所以在子进程中如果创立其他线程的话,其他线程是获取不到锁的,所以程序代码都会卡住,只有将子线程中将主线程的锁进行释放,子进程中其他子线程才会获取到锁并执行下去。
import multiprocessing
import threading
import time
def func():
print(“来了”)
with lock:
    print(666)
    time.sleep(1)
def task():
for i in range(10):
t = threading.Thread(target=func)
t.start()
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
lock = threading.RLock()
#
lock.acquire()
p1 = multiprocessing.Process(target=task)
p1.start()
‘’’
来了
来了
来了
来了
来了
来了
来了
来了
来了
来了
‘’’
#程序卡住了,运行不下去
将子线程中的主线程里的lock锁进行释放后,子线程可以正常执行代码。
import multiprocessing
import threading
import time
def func():
print(“来了”)
with lock:
    print(666)
    time.sleep(1)
def task():
for i in range(10):
t = threading.Thread(target=func)
t.start()
time.sleep(1)
lock.release()
if name == ‘__main__’:
multiprocessing.set_start_method(“fork”) #fork、spawn、forkserver
name = []
lock = threading.RLock()
#
lock.acquire()
p1 = multiprocessing.Process(target=task)
p1.start()
‘’’
来了
来了
来了
来了
来了
来了
来了
来了
来了
来了
666
666
666
666
666
666
666
666
666
666
‘’’
### (三)常见功能
#### 1、p.start()
当前进程准备就绪,等待被CPU调度(工作单元其实就是进程中的线程)
#### 2、p.join()
等待当前进程的任务执行完毕后再向下继续执行
import multiprocessing
from multiprocessing import Process
import threading
import time
def task(arg):
time.sleep(2)
print(“执行中。。。”)
if name == ‘__main__’:
multiprocessing.set_start_method(“spawn”) #fork、spawn、forkserver
p = Process(target=task, args=(‘xxx’, ))
p.start()
p.join()
print("继续执行。。。")
‘’’
执行中。。。
继续执行。。。
‘’’
#### 3、p.daemon()
是布尔值,守护进程(必须放在start之前)
p.daemon = True :设置为守护进程,主进程执行完之后,子进程也自动关闭。  
 p.daemon = False :设置为非守护进程,主进程等待子进程,子进程执行完之后,主进程才结束。
import multiprocessing
from multiprocessing import Process
import threading
import time
def task(arg):
time.sleep(2)
print(“执行中。。。”)
if name == ‘__main__’:
multiprocessing.set_start_method(“spawn”) #fork、spawn、forkserver
p = Process(target=task, args=(‘xxx’, ))
p.daemon = True
p.start()
print("继续执行。。。")
‘’’
继续执行。。。
‘’’
上述代码在执行完主进程之后就自动关闭了,子进程并没有得到执行。
#### 4、进程名称的设置和获取
import multiprocessing
from multiprocessing import Process
import threading
import time
def task(arg):
time.sleep(2)
print(“当前进程的名称:”, multiprocessing.current_process().name)
if name == ‘__main__’:
multiprocessing.set_start_method(“spawn”) #fork、spawn、forkserver
p = Process(target=task, args=(‘xxx’, ))
p.name = ‘new bee’
p.daemon = False
p.start()
print("继续执行。。。")
‘’’
继续执行。。。
当前进程的名称: new bee
‘’’
#### 5、自定义进程类
将进程定义为类,直接僵线程需要做的事儿写到run方法中
import multiprocessing
class MyProcess(multiprocessing.Process):
def run(self):
print(‘执行此进程’, self._args)
if name == ‘__main__’:
multiprocessing.set_start_method(‘spawn’)
p = MyProcess(args=(‘xxx’, ))
p.start()
print(“继续执行”)
‘’’
继续执行
执行此进程 (‘xxx’,)
‘’’
#### 6、获取进程和子进程id号
import multiprocessing
from multiprocessing import Process
import threading
import time
import os
def func():
time.sleep(1)
def task(arg):
for i in range(10):
t = threading.Thread(target=func)
t.start()
#time.sleep(2)
print(os.getpid(), os.getppid())
print(“当前进程的名称:”, multiprocessing.current_process().name)
print(len(threading.enumerate())) #获取线程个数
#11
if name == ‘__main__’:
print(os.getpid())
multiprocessing.set_start_method(“spawn”) #fork、spawn、forkserver
p = Process(target=task, args=(‘xxx’, ))
p.name = ‘new bee’
p.daemon = False
p.start()
print("继续执行。。。")
‘’’
8517 主进程id号
继续执行。。。
当前进程的名称: new bee
8558 子进程id号
8554 副进程id号
11
‘’’
#### 7、cpu的个数
为了利用cpu多核优势,一般需要看看有多少个cpu,定义相同数量的进程
import multiprocessing
print(multiprocessing.cpu_count())
#4
## 二、进程间数据的共享
进程是资源分配的最小单元,每个进程中都维护自己独立的数据,不共享。如果想要进程之间的数据进行共享,可以借助一些中介来实现。
当我们在子进程中修改列表数据时,主进程中的列表数据并没有发生变化,说明主进程和子进程之间是割裂的,数据并不共享。
import multiprocessing
def task(data):
data.append(666)
print(data) #[666]
if name == “__main__”:
data_list = []
p = multiprocessing.Process(target=task, args=(data_list,))
p.start()
p.join()
print("主进程:", data_list)
#主进程: []
### (一)共享
#### 1、share memory: Value / Array
通过Value和Array在子进程中更改元素的变量值,改变后的值同样也能共享到主进程中
字母所代表的含义:  
 ![请添加图片描述](https://ucc.alicdn.com/images/user-upload-01/direct/1fbc70a3391144f3ae42395040c9b871.jpeg)
from multiprocessing import Process, Value, Array
def func(n, m1, m2):
n.value = 888
m1.value = ‘a’.encode(‘utf-8’)
m2.value = “武”
if name == ‘__main__’:
num = Value(‘i’, 666)
v1 = Value(‘c’)
v2 = Value(‘u’)
p = Process(target=func, args=(num, v1, v2))
p.start()
p.join()
print(num.value) #888
print(v1.value) #a
print(v2.value) #武
Array可以更改数组的元素值
from multiprocessing import Process, Value, Array
def func(data_array):
data_array[0] = 666
if name == ‘__main__’:
arr = Array(‘i’, [11, 22, 33, 44, 55, 66]) #数组:元素类型必须是int
p = Process(target=func, args=(arr, ))
p.start()
p.join()
print(arr[:])
#[666, 22, 33, 44, 55, 66]
#### 2、Manager()
通过Manager来更改列表、字典的值
from multiprocessing import Process, Manager
def func(d, l):
d[‘高宇星’] = ‘18岁’
d[‘闫曦月’] = ‘68岁’
d[0.25] = None
l.append(666)
if name == ‘__main__’:
with Manager() as manager:
d = manager.dict()
l = manager.list()
p = Process(target=func, args=(d, l))
    p.start()
    p.join()
    print(d) #{'高宇星': '18岁', '闫曦月': '68岁', 0.25: None}
    print(l) #[666]
### (二)交换
#### 1、Queue
通过Queue将数据进行排队处理  
 ![请添加图片描述](https://ucc.alicdn.com/images/user-upload-01/direct/a741c797d714467abcc877f6b7e299b4.png)
import multiprocessing
def task(q):
for i in range(10):
q.put(i)

最后

Python崛起并且风靡,因为优点多、应用领域广、被大牛们认可。学习 Python 门槛很低,但它的晋级路线很多,通过它你能进入机器学习、数据挖掘、大数据,CS等更加高级的领域。Python可以做网络应用,可以做科学计算,数据分析,可以做网络爬虫,可以做机器学习、自然语言处理、可以写游戏、可以做桌面应用…Python可以做的很多,你需要学好基础,再选择明确的方向。这里给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

👉Python所有方向的学习路线👈

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

👉Python必备开发工具👈

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

👉Python全套学习视频👈

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

👉实战案例👈

学python就与学数学一样,是不能只看书不做题的,直接看步骤和答案会让人误以为自己全都掌握了,但是碰到生题的时候还是会一筹莫展。

因此在学习python的过程中一定要记得多动手写代码,教程只需要看一两遍即可。

👉大厂面试真题👈

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。


相关文章
|
11天前
|
IDE 测试技术 开发工具
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
在Python开发中,调试是提升效率的关键技能。本文总结了10个实用的调试方法,涵盖内置调试器pdb、breakpoint()函数、断言机制、logging模块、列表推导式优化、IPython调试、警告机制、IDE调试工具、inspect模块和单元测试框架的应用。通过这些技巧,开发者可以更高效地定位和解决问题,提高代码质量。
102 8
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
|
1天前
|
数据采集 消息中间件 Java
python并发编程:什么是并发编程?python对并发编程有哪些支持?
并发编程能够显著提升程序的效率和响应速度。例如,网络爬虫通过并发下载将耗时从1小时缩短至20分钟;APP页面加载时间从3秒优化到200毫秒。Python支持多线程、多进程、异步I/O和协程等并发编程方式,适用于不同场景。线程通信方式包括共享变量、消息传递和同步机制,如Lock、Queue等。Python的并发编程特性使其在处理大规模数据和高并发访问时表现出色,成为许多领域的首选语言。
|
25天前
|
存储 API 数据库
使用Python开发获取商品销量详情API接口
本文介绍了使用Python开发获取商品销量详情的API接口方法,涵盖API接口概述、技术选型(Flask与FastAPI)、环境准备、API接口创建及调用淘宝开放平台API等内容。通过示例代码,详细说明了如何构建和调用API,以及开发过程中需要注意的事项,如数据库连接、API权限、错误处理、安全性和性能优化等。
83 5
|
2月前
|
机器学习/深度学习 人工智能 关系型数据库
Python开发
Python开发
42 7
|
2月前
|
前端开发 安全 数据库
使用Python开发独立站的全面指南
本文详细介绍了如何使用Python及其Web框架Django和Flask快速搭建功能完善、易于管理的独立站。从Python和Web开发基础讲起,逐步覆盖环境搭建、项目创建、数据库设计、视图与URL路由、模板创建、表单处理、测试调试、部署优化及安全维护等内容,旨在帮助开发者高效构建稳定的Web应用。
73 1
|
2月前
|
JSON API 数据格式
如何使用Python开发天猫获得淘宝买家秀API接口?
本文介绍了如何使用Python开发天猫和淘宝买家秀API接口,包括注册开放平台账号、创建应用获取API权限、构建请求URL、发送请求获取响应及解析数据等步骤,帮助开发者高效获取和处理商品信息与用户评价数据。
37 0
|
存储 iOS开发 MacOS
100 个基本 Python 面试问题第四部分(57-68)
100 个基本 Python 面试问题第四部分
166 0
100 个基本 Python 面试问题第四部分(57-68)
|
监控 大数据 Python
100 个基本 Python 面试问题第七部分(91-100)
100 个基本 Python 面试问题第七部分
179 0
|
存储 Java 测试技术
100 个基本 Python 面试问题第六部分(81-90)
100 个基本 Python 面试问题第六部分
131 0
|
存储 Python
100 个基本 Python 面试问题第五部分(69-80)
100 个基本 Python 面试问题第五部分
148 0