python基础(六)
进程和线程
进程
进程就是操作系统中执行的一个程序,操作系统以进程为单位分配存储空间,每个进程都有自己的地址空间、数据栈以及其他用于跟踪进程执行的辅助数据,操作系统管理所有进程的执行,为它们合理的分配资源。创新的进程有自己独立的内存空间,因此必须通过进程间通信机制(IPC,Inter-Process Communication)来实现数据共享,具体的方式包括管道、信号、套接字、共享内存区等。
验证进程独立空间
import multiprocessing
import os
#验证父进程在创建子进程时复制了进程及其数据结构每个进程都有自己独立的内存空间
def process_func(value):
# 在这个函数内部,尝试修改全局变量,但是这是在不同的内存空间中
global_var = value
global_var += 1
print(f"son PID {multiprocessing.current_process().pid}: global_var = {global_var}")
if __name__ == "__main__":
# 主进程中的全局变量
global_var = 0
# 创建并启动一个子进程
p = multiprocessing.Process(target=process_func, args=(global_var,))
p.start()
p.join() # 等待子进程完成
# 主进程中打印全局变量的值
print(f"Main process PID: {os.getpid()}, global_var = {global_var}")
#son PID 22916: global_var = 1
#Main process PID: 70036, global_var = 0
进程通信
import multiprocessing
import os
def sub_task(queue):
print('子进程进程号:', os.getpid()) #子进程进程号: 3xxx
for i in range(1,5):
queue.put(i) #将元素放在队列的末尾
if __name__ == '__main__':
print('主进程号:', os.getpid()) #主进程号: xxx
queue = multiprocessing.Queue()
p = multiprocessing.Process(target=sub_task, args=(queue,))
p.start()
counter = 0
for i in 'ABCD':
queue.put(i)
p.join() #子任务已经完成
for _ in range(8):
print(queue.get(), end='') #ABCD1234
线程
一个进程还可以拥有多个并发的线程,简单的说就是拥有多个可以获得CPU调度的执行单元,这就是所谓的线程。由于线程在同一个进程下,它们可以共享相同的上下文,因此相对于进程而言,线程间的信息共享和通信更加容易。当然在单核CPU系统中,真正的并发是不可能的,因为在某个时刻能够获得CPU的只有唯一的一个线程,多个线程共享了CPU的执行时间。
线程数据共享
import threading
from threading import Thread
# 全局变量 主线程中创建了一个全局变量,那么这个变量对于所有的其他线程来说也是可见的
g_num = 0
lock = threading.Lock() #使用了一个锁lock来确保每次只有一个线程可以修改 g_num
def thread_function():
global g_num #每个线程都能看到 g_num 的变化
with lock: #with 语句保证在执行增加操作的时候lock会被自动获取和在操作完成后自动释放
g_num += 1
print(f"Thread {threading.get_ident()}: g_num = {g_num}")
def main():
t = Thread(target=thread_function)
t.start()
t1 = Thread(target=thread_function)
t1.start()
t.join()
t1.join()
if __name__ == "__main__":
main()
对比
import threading
from multiprocessing import Process
import time
lock=threading.Lock()
global_v=0
def show_fuc_without_lock():
global global_v
global_v+=1
print(global_v)
def show_fuc_with_lock():
global global_v
global_v+=1
print(global_v)
def show_fuc(name):
for i in range(6):
print(name,end=' ')
time.sleep(1)
print(i)
def print_fuc(name):
for i in 'abcde':
print(name,end=' ')
time.sleep(1)
print(i)
if __name__=='__main__':
th1=threading.Thread(target=show_fuc, args=('show_fuc',))
th2=threading.Thread(target=print_fuc,args=('print_fuc',))
th1.start() #多个线程完成多个任务
th2.start() #多个线程完成多个任务
th1.join()
th2.join()
# p1=Process(target=show, args=('p_show',))
# p2=Process(target=show1, args=('p_show1',))
# p1.start() #多进程的并行执行
# p2.start()
# threads = [threading.Thread(target=show_fuc_lock) for _ in range(10)]
# for t in threads:
# t.start()
# 等待所有线程完成
# for t in threads:
# t.join()
pickling和unpickling
pickling将一个python对象转换为一个字节流以便将其存储到文件中或通过网络传输 | unpickling是将字节流重新转换回原来的python对象 |
|
python内存管理机制
python里内存管理主要依赖于自动内存管理机制,特别是垃圾回收机制,python使用引用计数和垃圾回收相结合的方式来管理内存;每个对象的引用次数将为零时python会立即回收相关内存;python内置的垃圾回收器专门处理引用循环的问题。
python程序退出时,不一定能释放所有内存,python的垃圾回收器尝试回收不再使用的内存,但是由于一些引用循环依赖于垃圾回收发现和处理,程序退出时并不保证足够的时间处理所有循环引用;还有一些外部C库的资源管理问题,C库可能分配程序一些内存,python退出时并不负责清理这些外部库分配的内存,需要依赖这些库本身提供的清理机制否则会有内存泄漏,防止内存泄漏可以使用上下文管理器来管理资源,比如使用with open() as file确保文件操作后文件会自动关闭,尽量减少全局变量的使用及时清理不再需要的对象。
python的深拷贝与浅拷贝
浅拷贝:拷贝父对象,不会拷贝对象内部的子对象。深拷贝:拷贝父对象以及对象内部的所有子对象。在Python中,可以使用copy
模块来实现浅拷贝和深拷贝。浅拷贝使用copy
模块的copy
函数:
import copy
original_list = [1, 2, [3, 4]]
shallow_copy = copy.copy(original_list)
deep_copy=copy.deepcopy(original_list)
print(original_list) # 输出: [1, 2, [3, 4]]
print(shallow_copy) # 输出: [1, 2, [3, 4]]
print(deep_copy) # 输出: [1, 2, [3, 4]]
original_list[2][0]=0
print(original_list) # 输出: [1, 2, [0, 4]]
print(shallow_copy) # 输出: [1, 2, [0, 4]]
print(deep_copy) # 输出: [1, 2, [3, 4]]
python3 VS python2
打印语句 | p2里print是语句print”hell“, p3里print变为一个函数print(”hell“) |
整数除法 | p2里5/2=2, p3里5/2=2.5 |
字符串 | p2里默认字符串类型是ASCII,文件编码需要显示声明coding=utf-8,p3是默认类型是Unicode,默认文件编码utf-8 |
内置函数变化 | p2里range() 返回一个列表, p3返回迭代器,你需要list(range(2))返回列表 |
库的改进 | p3对许多内置库和语法进行改进和简化,提升可读性和性能如urllib, input()函数 |
异常处理 | p2写异常except SomeException,e ; p3使用except SomeException as e |
数据类型 | p3增加新数据类型如bytes,处理字节数据,还引进了诸如functools。pathlib |
迭代器和生成器 | p3对迭代器和生成器进一步优化,提高了性能,如map(), filter(),zip()等在p3中返回迭代器,p2里返回时列表 |