python之多进程线程相关总结

多进程

Process类

定义

#获取当前CPU的内核数量
import multiprocessing #多进程模块
print(multiprocessing.cpu_count()) #获取cpu的可用数量

#多进程的定义利用multiprocessing模块中的Process类
"""
属性:
pid:进程id
name:进程名

构造:
def __init__([group [,target [,name [,args [,kwargs [,daemon ]]]]]])
group 分组定义
target 进程处理对象(代替run())
name 进程名(不设置则自动分配)
args 进程处理对象所需要的执行参数,参数传递args = (num1,num2,)中最后一位的","不能缺省
kwargs 调用对象字典
daemon 是否设置为后台进程

方法:
start(self):进程启动,进入进程调度队列
run(self):进程处理(不指定target时起效)
"""
# multiprocessing.current_process().pid 获取当前进程的信息(pid,name)
import multiprocessing,time
def pro_work(num): #进程处理方法
	"""获取当前执行进程的id及name
	"""
	print("进程id:%s,进程名:%s,数据:%s" % (multiprocessing.current_process().pid, 
	multiprocessing.current_process().name), num)
	time.sleep(num) #延迟操作
def main():
	for i in range(5):
		#创建进程对象
		process = multiprocessing.Process(target=pro_work, args=(5,), name="test%s" % i)
		process.start() #进程启动

进程处理类

#以面向对象形式进行进程的创建,直接继承Process类,同时覆写内部的run()方法
import multiprocessing,time
class myprocess(multiprocessing.Process):
    def __init__(self, name, num):
        super().__init__(name=name) #调用父类构造设置进程名称
        self.__num=num
    def run(self):
        print("%s:%s" % (multiprocessing.current_process().name, self.__num))
        time.sleep(self.__num)
def main():
    for i in range(3):
        process = myprocess(name="test%s" % i, num=2)
        process.start()
if __name__ == "__main__":
    main()
"""
test0:2
test1:2
test2:2
"""

start()与run()

#start()方法调用之后实际调用的全是run()方法的方法体
#若直接使用run()方法进行进程的调用,最终可以执行的只能是当前进程的一个信息获取而没有启动新进程
import multiprocessing
class myprocess(multiprocessing.Process):
    def __init__(self, name, num):
        super().__init__(name=name) #调用父类构造设置进程名称
        self.__num=num
    def run(self):
        print("%s:%s:%s" % (multiprocessing.current_process().pid,
                            multiprocessing.current_process().name, self.__num))
def main():
    process = myprocess(name="test%s" % "001", num=2)
    process.start()
    process.run()
if __name__ == "__main__":
    main()
"""
12688:MainProcess:2        #主进程,通过process.run()执行的结果
13276:test001:2
"""

进程控制

"""
terminate(self):关闭进程
is_alive(self):判断进程是否存活
join(self,timeout):进程强制执行,即强占cpu资源
"""
import multiprocessing,time
def pro_work(num):
	time.sleep(num)
	print("进程id:%s,进程名:%s,数据:%s" % (multiprocessing.current_process().pid, 
	multiprocessing.current_process().name), num)
def main():
	process = multiprocessing.Process(target=pro_work, args=(5,), name="test")
	process.start()
	process.join()
	print("进程id:%s,进程名:%s" % (multiprocessing.current_process().pid, 
	multiprocessing.current_process().name))
#join()后,此时子进程先执行完毕,若子进程占用时间时间较长,其他进程需要进行等待,当子进程全部执行完毕后,主进程才会继续执行,即子进程使用join()强占了cpu资源

#进程中断
if process.is_alive():
	process.terminate()
	print("%s中断" % process.name)

守护进程(Daemon)

#在后台执行的进程,随着创建它的主进程的存在而存在,随着创建它的主进程的消失而消失
#一般可作为后台进程的监控或服务处理而使用
import multiprocessing,time
def status():
	while True: #守护进程持续执行
		print("守护进程:%s" % multiprocessing.current_process().pid)
		time.sleep(1)
def pro_work():
	daemon_process = multiprocessing.Process(target=status,name="守护进程",daemon=True)
	daemon_process.start()
	for i in range(5):
		print("业务进程")
		time.sleep(2)
def main():
	process = multiprocessing.Process(target=pro_work, name="test")
	process.start()

fork

#通过"os.fork()"的方式创建子进程,并不是跨平台形式的
#windows版本的python不支持此操作,linux/unix下可以使用fork底层函数支持(uname -a命令查看当前系统运行环境)
import os
def myfork():
	print("父进程id:%s, 子进程id:%s" % (os.getppid(), os.getpid()))
def main():
	p = os.fork()
	#创建失败p<0;p>0表示父进程;p==0表示子进程
	if p == 0:
		myfork()
	else:
		print("父进程")

进程管理(psutil)

psutil是进程管理的第三方模块(需要安装),可跨平台

#获取全部进程信息
#交互模式下:psutil.test(),直接进行所有进程信息内容获取
import psutil
for i in psutil.process_iter(): #获取全部进程
	print("进程编号:%d, 进程名:%s, 创建时间:%s" % (
		i.pid,
		i.name(),
		i.create_time()
	))
	#杀死进程
	if i.name() == "xxxx.exe":
		i.terminate()

#获取系统硬件的相关信息
#获取cpu信息
import psutil
print("物理cpu数量:%d" % psutil.cpu_count(logical=False))
print("逻辑cpu数量:%d" % psutil.cpu_count(logical=True))
print("用户cpu使用时间:%f,系统cpu使用时间:%f,cpu空闲时间:%s" % 
	psutil.cpu_times().user, psutil.cpu_times().system, psutil.cpu_times().idle
)
for i in range(5):
	print("cpu使用率监控:%s" % psutil.cpu_percent(interval=1,percpu=True))
	#每隔一秒进行每个cpu的监控

#获取磁盘信息
print("磁盘分区:获取全部磁盘信息:%s" % psutil.disk_partitions())
print("磁盘使用率:获取D磁盘使用率:%s" % str(psutil.disk_usage("d:")))#默认C盘
print("磁盘IO:获取磁盘IO使用率:%s" % str(psutil.disk_io_counters()))

#获取网络信息
print("数据统计:网络数据交互信息:%s" % str(psutil.net_io_counters()))
print("网络接口信息:%s" % str(psutil.net_if_addrs()))
print("网络接口状态:%s" % str(psutil.net_if_stats()))

进程池

为保证多进程与操作系统性能之间的平衡问题,将多个进程放入一个池中进行统一管理,保障不会产生过多进程影响硬件性能

# multiprocessing的Pool类
import os,time
from multiprocessing import Pool
def tmppro(num):
	print("%s:%s" % (os.getpid(), num))
	return "%s:%s" % (os.getpid(), num)
def main():
	p = Pool(processes = 3) #创建3个进程的进程池
	data = []
	for i in range(9):
		r = p.apply_async(func = tmppro, args = (i,)) ## apply_async(func, args) 任务加入进程池(异步),func函数,args元组,传入函数的参数
		#可以获取返回值
		print(r.get()) #获取进程处理函数的返回结果
		data.append(r)
	#time.sleep(10)
	#进程池是主进程创建的,会随着主进程的关闭而关闭,进程池内的进程会随着进程池的关闭而关闭
	p.close() # 关闭进程池,不再接受新请求
	p.join() # 等待进程池任务结束,要close()之后在再调用
	for j in data:
		print(j.get())
#创建的普通进程,通过进程模块执行的函数无法获取返回值

进程通讯

pipe(管道)

import multiprocessing
def sendData(con, data):
	con.send(data) #通过管道发送数据
def reviceData(con):
	print(con.recv()) #接收通过管道发来的数据
def main():
	se, re = multiprocessing.pipe() #创建两个管道,发送与接受
	process_send = multiprocessing.Process(target = sendData, args = (se, "abc"))
	process_revice = multiprocessing.Process(target = reviceData, args = (se, ))
	process_send.start()
	process_revice .start()

进程队列
在发送数据过多、接收处理缓慢时,可以在不同进程间以队列的形式进行缓冲的操作实现

#多进程模块中的队列类Queue
"""
def __init__(self, maxsize = 0, *, ctx) 构造, 设置队列保存最大长度
put(self, obj, block = True, timeout = None) 插入数据
get(self, block = True, timeout = None) 获取数据
qsize(self) 获取队列保存数据个数
empty(self) 是否为空
full(self) 是否为满

block是队列的阻塞配置,默认True,False是非阻塞模式,在队列数据满了或空了进行插入或获取会抛出异常,True会等待到timeout时间到达后才会抛出异常
timeout是阻塞超时时间(秒)
"""
import multiprocessing
def sendData(queue):
	for i in range(100):
		queue.put("test:%s" % i)
def reviceData(queue):
	while True
		print("%s" % queue.get())
def main():
	queue = multiprocessing.Queue() #创建进程延迟队列
	process_send = multiprocessing.Process(target = sendData, args = (queue, ))
	process_revice = multiprocessing.Process(target = reviceData, args = (queue, ))
	process_send.start()
	process_revice .start()
	process_send.join()
	process_revice .join()
#由于windows权限分配问题,可能会出现"PermissionError:[WinError 5] 拒绝访问"的异常信息,以管理员身份运行或在命令行操作即可

subprocess
可采用管道的形式去启动操作系统中另外的一个进程,并获得该进程的相关信息

#subprocess中的输入输出都是通过管道
#subprocess模块直接进行call()函数调用即可,call()可以直接调用命令
"""
def call(*popenargs, timeout = None, **kwargs)
"""
import subprocess
def main():
	subprocess.call("ls -l", shell = True) #允许执行shell程序

#Popen类
"""
def __init__(...)

args:要执行的shell命令或命令列表
bufsize:缓冲区大小
stdin、stdout、stderr:标准输入、标准输出、错误输出
shell:是否直接执行命令。若设为True表示可以直接执行
cwd:当前的工作目录
env:子进程环境变量
"""
subprocess.Popen("mkdir test", shell = True, cwd = ".") #设置命令以及它的执行路径
#定时关闭进程
p = subprocess.Popen("test.exe")
time.sleep(5)
p.kill() #销毁

#可以直接使用标准输入、标准输出、错误输出,进行进程的数据通信操作
p = subprocess.Popen("python.exe", stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
#和命令交互
p.stdin.write("s = 'abcd'\n".encode())
p.stdin.write("print('%s' % s)\n".encode()) #向命令行输入,encode二进制的编码转换
p.stdin.close() #关闭输入流
outer = p.stdout.read() #读取信息返回
p.stdout.close()
print(outer.decode()) #正确数据
outererr = p.stderr.read() #读取信息返回
p.stderr.close()
print(outererr.decode()) #错误数据

Manager类

#该类中数据交互的存储类型:列表、字典,跨进程的数据处理
import multiprocessing
def work_pro(li):
	li.append("%s" % multiprocessing.current_process().name)
def main():
	ma = multiprocessing.Manager() #创建共享数据对象
	m_list = ma.list(["abcd"]) #m_list是一个可以被多个进程共享的列表
	pro_a = multiprocessing.Process(target = work_pro, args = (m_list,), name = "proa")
	pro_b = multiprocessing.Process(target = work_pro, args = (m_list,), name = "prob")
	pro_a.start()
	pro_b.start()
	pro_a.join()
	pro_b.join()
	print("%s" % m_list)

#dict字典也可以
"""
...
ma = multiprocessing.Manager()
m_dict = ma.dict("abc" = "123")
...
"""

进程同步

Lock,同步锁机制
可以实现对临界资源的同步锁定,保证同一时刻只有一个进程对临界资源进行访问操作

"""
def acquire(self, blocking = True, timeout = -1) 获取锁,若当前没有可用锁资源,则进行阻塞等待
def release(self) 释放锁资源
"""
lock = multiprocessing.Lock() #定义一个进程的同步锁
#在需要同步的地方进行如下操作
lock.acquire(timeout = 3) #加锁,3秒内若没有锁定就放弃,成功获取锁返回True,否则False
#...
lock.release() #解锁,释放锁资源
#程序中加锁,会导致部分代码只能以单进程形式执行,会导致部分的程序性能的下降,因此只有在考虑数据操作安全的情况下才会使用锁机制

Semaphore(信号量)
有限资源的进程同步管理机制,带有计数功能(acquire减少计数,release增加计数),可用信号量计数为0时,后续进程阻塞

import multiprocessing
sem = multiprocessing.Semaphore(3) #只允许3个进程并发执行
#在业务处理方法中使用
if sem.acquire():
    #...
    sem.release()
#针对于有限资源实现的部分进程的并发处理

Event
同步的处理事件,多个进程拥有同一个Event实例,调用wait()时进入阻塞状态,同时设置阻塞标记False,阻塞标记为True时才会解除阻塞状态,此时另一个进程继续执行,且通过set()将阻塞标记设为True,这样之前的阻塞进程才会继续执行

#打印abcd
import multiprocessing
def work_a(event):
    print("a")
    event.set()  # 解除阻塞状态
    event.clear()  # 清除已有状态
    event.wait()
    print("c")
    event.set()
    event.clear()  # 每次清除,避免出现结构混乱

def work_b(event):
    event.wait()  # 进入阻塞状态
    print("b")
    event.set()
    event.clear()  # 清除之前状态
    event.wait()
    print("d")

def main():
    event = multiprocessing.Event()
    proa = multiprocessing.Process(target=work_a, args=(event,), name="proa")
    prob = multiprocessing.Process(target=work_b, args=(event,), name="prob")
    proa.start()
    prob.start()
#两个进程协作同步处理操作

Barrier
表示的是一种屏障,当若干进程未达到屏障数量时都处于阻塞状态,当达到屏障数量时,将自动解除阻塞状态并同时启动运行

import multiprocessing
def barrier_work(): #栅栏处理函数
    print("run")
def pro_work(barrier):
    print("wait")
    barrier.wait() #进入到一个屏障点等待
    print("ok")
def main():
    barrier = multiprocessing.Barrier(parties=3, action=barrier_work) #每有3个进程则调用相应处理方法
    pro_list= [multiprocessing.Process(target=pro_work, args=(barrier, )) for i in range(10)]
    for j in pro_list:
        j.start()
    for j in pro_list:
        j.join()
    barrier.abort() #结束同步栅栏的锁定
main()

多线程

python中的多线程并没有特别高效的处理性能,因为python有一个GIL全局锁问题
windows下进入windows管理工具:wmic
查看cpu信息:cpu get Name
查看cpu物理核心数量:cpu get NumberOfCores
查看cpu逻辑核心数量(超线程技术:一核cpu模拟出两核的线程):cpu get NumberOfLogicalProcessors
linux下:
grep ‘physical id’ /proc/cpuinfo 查看cpu数量
grep ‘core id’ /proc/cpuinfo 查看cpu核心数量
grep ‘processor’ /proc/cpuinfo 查看支持的线程数量

_thread

早期的python提供的多线程开发模块,新的python开发不再使用

import _threaed,time
def thread_work(name): #线程处理函数
	print("%s is running" % name)
def main():
	for i in range(5):
		_thread.start_new_thread(thread_work, ("test%s" % i)) #创建并启动线程
	time.sleep(10)

threading

目前多线程开发使用的模块,提供了大量方便的处理类,方便进行线程同步的控制

"""
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None)
group:分组定义
target:线程处理对象
name:线程名,不设置则自动分配
args:线程处理对象所需参数
kwargs:调用对象字典
daemon:是否设置为后台线程

def start(self) 线程启动
def run(self) 线程操作实体,若未设置target,则执行该方法
def join(self, timeout=None) 线程强制执行
def name(self) 获取线程名
def ident(self) 获取线程标识
def is_alive(self) 判断线程存活状态
"""
import threading
def thread_work(num): #线程处理函数
	print("%s is running: %s" % (threading.current_thread().name, num))
def main():
	for i in range(5):
		thread = threading.Thread(target=thread_work, args=(i,), name = "testthread%s" % i)#创建线程对象
		thrad.start()
	print("线程id:%s,线程名:%s" % (threading.current_thread().ident, threading.current_thread().name))
	print("当前线程存活个数:%s" % threading.active_count())
	print("当前活跃线程信息:%s" % threading.enumerate())

#定义线程类进行处理,需要覆写run()方法
import threading,time
class mythread(threading.Thread):
	def __init__(self, tname, num)
		super().__init__(name=tname) #将线程名称传递到父类构造
		self.__num = num
	def run(self):
		print("%s:%s" % (threading.current_thread().getName(), self.__num))
def main():
	for i in range(5):
		thread = mythread("thread%s" % i, i)
		thrad.start()

#后台线程
def main():
	thread = mythread("threadtest", 5)
	daemon_thread = mythread("daemon thread", 0)
	daemon_thread.setDaemon(True) #将该线程设为守护线程
	thrad.start()
	daemon_thread.start()

线程同步

threading提供有Lock&RLock(锁)、Event(同步事件)、Semaphore&BoundedSemaphore(边界信号量)、Barrier(栅栏)

#总体操作与进程同步差不多
import threading
def work(semaphore):
	if semaphore.acquire():
		print("%s" % threading.current_thread().name)
		semaphore.release()
def main():
	semaphore = threading.Semaphore(3) #获取信号量
	thread_list = [threading.Thread(target=work, args=(semaphore, ), name="test%s" % i) for i in range(10)]
	for j in thread_list:
		j.start()

#Lock若重复锁定且没有进行指定次数的解锁,会发生死锁,但RLock不论锁定多少次,一次就可以全部解锁
import threading
num = 4
def work(lock):
	global num #使用全局变量
	if lock.acquire():
		if num > 0:
			print("%s:%s" % (threading.current_thread().name, num))
			num -= 1
		lock.release()
def main():
	lock = threading.RLock() #RLock有自动的全部解锁操作
	thread_list = [threading.Thread(target=work, args=(lock, ), name="test%s" % i) for i in range(10)]
	for j in thread_list:
		j.start()

定时调度

python提供sched模块实现自动调度

import threading, sched
def work(schedule):
    """
    delay:延时,秒
    priority:优先级
    action:处理方法
    argument:参数
    """
    print("%s" % threading.current_thread().name)
    schedule.enter(delay=1,priority=0,action=work,argument=(schedule,)) #延迟1秒继续执行
def main():
    schedule = sched.scheduler() #创建定时调度
    schedule.enter(delay=0,priority=0,action=work,argument=(schedule,))
    schedule.run() #启动定时调度的线程

生产者消费者模型

import threading,time
class Message: #数据的描述类型
    def __init__(self):
        self.__title = None
        self.__content = None
    def set_info(self, title, content):
        self.__title = title
        time.sleep(1) #进行操作的生产延迟
        self.__content = content
        print("%s: title:%s, content:%s" % (threading.current_thread().name, self.__title, self.__content))
    def __str__(self): #获取数据将由消费者负责
        time.sleep(0.8) #消费者的延迟时间短
        return "%s: title:%s, content:%s" % (threading.current_thread().name, self.__title, self.__content)
def producer(message): #生产者处理函数
    for num in range(10): #生成10组数据
        if num % 2 == 0: #交替生产
            message.set_info("a", "001")
        else:
            message.set_info("b", "002")
def consumer(message): #消费者处理函数
    for num in range(10):
        print(message) #获取10次数据
def main():
    message = Message() #公共保存的数据对象
    producer_thread = threading.Thread(target=producer, name="生产者线程", args=(message,))
    consumer_thread = threading.Thread(target=consumer, name="消费者线程", args=(message,))
    producer_thread.start()
    consumer_thread.start()
    """
消费者线程: title:a, content:None
生产者线程: title:a, content:001
消费者线程: title:b, content:001
生产者线程: title:b, content:002
消费者线程: title:a, content:002
生产者线程: title:a, content:001
消费者线程: title:b, content:001
生产者线程: title:b, content:002
消费者线程: title:a, content:002
消费者线程: title:a, content:002
生产者线程: title:a, content:001
消费者线程: title:b, content:001
生产者线程: title:b, content:002
消费者线程: title:a, content:002
生产者线程: title:a, content:001
消费者线程: title:b, content:001
生产者线程: title:b, content:002
消费者线程: title:a, content:002
生产者线程: title:a, content:001
生产者线程: title:b, content:002
    """
if __name__ == '__main__':
    main()

Condition

实现等待与唤醒的处理机制,通过threading模块的Condition处理类完成

import threading,time
class Message: #数据的描述类型
    def __init__(self, condition):
        self.__title = None
        self.__content = None
        self.__condition = condition
        #flag==True可以生产不能消费,False可以消费不能生产
        self.__flag = True
    def set_info(self, title, content):
        self.__condition.acquire() #获取同步锁
        if self.__flag == False:
            self.__condition.wait() #当前线程进入阻塞状态,线程等待
        self.__title = title
        time.sleep(1)
        self.__content = content
        print("%s: title:%s, content:%s" % (threading.current_thread().name, self.__title, self.__content))
        self.__flag = False
        self.__condition.notify() #唤醒一个其他等待的线程
        #def notify_all(self) 唤醒所有等待线程
        self.__condition.release() #释放锁
    def __str__(self):
        self.__condition.acquire()
        if self.__flag==True:
            self.__condition.wait() #等待生产者生产数据
        try:
            time.sleep(0.8)
            return "%s: title:%s, content:%s" % (threading.current_thread().name, self.__title, self.__content)
        finally:
            self.__flag = True
            self.__condition.notify()
            self.__condition.release()
def producer(message): #生产者处理函数
    for num in range(10):
        if num % 2 == 0:
            message.set_info("a", "001")
        else:
            message.set_info("b", "002")
def consumer(message): #消费者处理函数
    for num in range(10):
        print(message)
def main():
    condition = threading.Condition() #实例化条件锁
    """
    def __init__(self,lock=None)设置锁类型,若不设置则使用RLock锁
    """
    message = Message(condition) #公共保存的数据对象
    producer_thread = threading.Thread(target=producer, name="生产者线程", args=(message,))
    consumer_thread = threading.Thread(target=consumer, name="消费者线程", args=(message,))
    producer_thread.start()
    consumer_thread.start()
    """
生产者线程: title:a, content:001
消费者线程: title:a, content:001
生产者线程: title:b, content:002
消费者线程: title:b, content:002
生产者线程: title:a, content:001
消费者线程: title:a, content:001
生产者线程: title:b, content:002
消费者线程: title:b, content:002
生产者线程: title:a, content:001
消费者线程: title:a, content:001
生产者线程: title:b, content:002
消费者线程: title:b, content:002
生产者线程: title:a, content:001
消费者线程: title:a, content:001
生产者线程: title:b, content:002
消费者线程: title:b, content:002
生产者线程: title:a, content:001
消费者线程: title:a, content:001
生产者线程: title:b, content:002
消费者线程: title:b, content:002
    """
if __name__ == '__main__':
    main()

线程操作队列

在程序开发中,队列属于一种缓冲结构
引用队列是一种提高生产者处理性能的必要设计手段,可以解决数据过多而消费过慢的问题

"""
数据缓冲区的实现可以依靠queue模块,它提供了三种线程同步队列类的定义
queue.Queue:先进先出(FIFO)同步队列
queue.LifoQueue:后进先出(LIFO)同步队列
queue.PriorityQueue:优先级队列
"""
#以Queue为例:
import threading,time,queue
class Message: #数据的描述类型
    def __init__(self):
        self.__title = None
        self.__content = None
    def set_info(self, title, content):
        self.__title = title
        time.sleep(0.1)
        self.__content = content
        print("%s: title:%s, content:%s" % (threading.current_thread().name, self.__title, self.__content))
    def __str__(self):
        time.sleep(0.8)
        return "%s: title:%s, content:%s" % (threading.current_thread().name, self.__title, self.__content)
def producer(qu): #生产者处理函数
    for num in range(10):
        message = Message() #定义生产数据的包装类型
        if num % 2 == 0:
            message.set_info("a", "001")
        else:
            message.set_info("b", "002")
        qu.put(message) #向队列中保存数据
def consumer(qu): #消费者处理函数
    for num in range(10):
        print(qu.get()) #通过队列获取数据
def main():
    qu = queue.Queue(5) #定义一个5个大小的队列,队列中保存message对象
    producer_thread = threading.Thread(target=producer, name="生产者线程", args=(qu,))
    consumer_thread = threading.Thread(target=consumer, name="消费者线程", args=(qu,))
    producer_thread.start()
    consumer_thread.start()
    """
生产者线程: title:a, content:001
生产者线程: title:b, content:002
生产者线程: title:a, content:001
生产者线程: title:b, content:002
生产者线程: title:a, content:001
生产者线程: title:b, content:002
生产者线程: title:a, content:001
消费者线程: title:a, content:001
生产者线程: title:b, content:002
消费者线程: title:b, content:002
生产者线程: title:a, content:001
消费者线程: title:a, content:001
生产者线程: title:b, content:002
消费者线程: title:b, content:002
消费者线程: title:a, content:001
消费者线程: title:b, content:002
消费者线程: title:a, content:001
消费者线程: title:b, content:002
消费者线程: title:a, content:001
消费者线程: title:b, content:002
    """
if __name__ == '__main__':
    main()

"""
def qsize(self) 返回队列大小
def empty(self) 是否为空队列,空返回True
def full(self) 队列是否已满,满返回True
def join(self) 强制等待队列为空后再执行后续操作
"""

多协程编程

python主要依靠协程去解决整体的性能问题
协程(微线程、纤程),协作式程序,是比线程还要小的控制单元,所有的协程都是通过线程创建的,本身不受操作系统环境控制,全由开发者进行控制,不论进程或线程都会受到各种轮转处理的操作问题(即让出cpu资源),这样的处理过程中会造成许多不必要的性能开支
进程或线程是系统级实现,协程是程序级实现
进程或线程由操作系统控制切换,协程则由开发者控制切换
切换内容:进程(页全局目录、内核栈、硬件上下文),线程(内核栈、硬件上下文),协程(硬件上下文)
进程或线程的切换内容保存在内核栈,协程的切换内容由开发者定义保存位置
进程或线程切换需要陷入内核态,协程始终在用户态,协程的切换效率最高
在python提供的并发编程中,多协程开发是性能最高的实现形式

#yield实现多协程
def producer(con): #生产者
    info= None #生产数据
    con.send(info) #必须首先发送一个None数据
    #否则会报错,类型错误:无法将非 None 值发送到刚启动的生成器
    for i in range(5):
        if i%2==0:
            info = "a"
        else:
            info = "b"
        print("producer:%s" % info)
        con.send(info) #将数据发送给消费者
def consumer(): #消费者
    while True:
        ret = yield #等待数据的接收
        print("consumer:%s" % ret)
def main():
    con = consumer() # 定义消费者
    producer(con)
if __name__ == '__main__':
    main()
"""
producer:a
consumer:a
producer:b
consumer:b
producer:a
consumer:a
producer:b
consumer:b
producer:a
consumer:a
"""
#当前的程序开发没有任何的系统级的处理控制,多进程或多线程都要一定的受到操作系统的各种状态控制

greenlet

python提供的多协程开发的模块支持,可以简化yield对于多协程处理的细节操作(每次都需要send()进行发送处理),可以使用greenlet进行处理包装

import greenlet #需要安装
info= None #保存生产数据
def producer(): #生产者
    global info
    for i in range(5):
        if i%2==0:
            info = "a"
        else:
            info = "b"
        print("producer:%s" % info)
        consumer_greenlet.switch() #切换到消费者
def consumer(): #消费者
    while True:
        print("consumer:%s" % info)
        producer_greenlet.switch() #切换到生产者
producer_greenlet = greenlet.greenlet(run=producer) #类,定义协程切换函数
consumer_greenlet = greenlet.greenlet(run=consumer)
def main():
    producer_greenlet.switch() #生产者首先执行
if __name__ == '__main__':
    main()
"""
producer:a
consumer:a
producer:b
consumer:b
producer:a
consumer:a
producer:b
consumer:b
producer:a
consumer:a
"""

gevent

为进一步简化协程开发,python提供了第三方模块gevent,使用greenlet协程开发时需要手动进行切换处理,gevent可以进行自动切换(需要设置触发条件),为防止程序执行过快,greenlet可能需要进行time.sleep()的延迟操作再手动switch(),但gevent本身提供有sleep函数,在休眠时自动延迟切换

import gevent#需要安装
info= None #保存生产数据
def producer(): #生产者
    global info
    for i in range(5):
        if i%2==0:
            info = "a"
        else:
            info = "b"
        print("producer:%s" % info)
        gevent.sleep(1) #延迟时间到后进行切换
def consumer(): #消费者
    while True:
        print("consumer:%s" % info)
        gevent.sleep(1) #切换到生产者
def main():
    producer_gevent = gevent.spawn(producer) #定义协程对象
    consumer_gevent = gevent.spawn(consumer)
    producer_gevent.join()#协程启动
    consumer_gevent.join()
if __name__ == '__main__':
    main()
"""
producer:a
consumer:a
producer:b
consumer:b
producer:a
consumer:a
producer:b
consumer:b
producer:a
consumer:a
consumer:a
consumer:a
consumer:a
consumer:a
......
"""

文件操作

"""
def open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)
file文件路径
mode文件操作模式
r:只读,文件不存在则报错,w:只写文件存在则覆盖,不存在则创建,x:写模式,新建一个文件,文件已存在则报错
a:追加,b:二进制模式,t:文本模式(默认),+:打开文件进行更新(可读可写)
buffering设置缓冲区大小
encoding文件操作编码
errors设置报错级别(是否需要强制处理'strict',忽略错误'ignore')
newline换行符设置
closefd设置文件关闭模式,若传进来路径为文件,表示结束时要关闭文件(设为True)
"""
try:
	f = open("d:\\test.txt", "r")
	print("文件名:%s" % f.name)
	print("文件是否关闭:%s" % f.closed)
	print("文件访问模式:%s" % f.mode)
finally:
	f.close()
#所有IO的文件对象都是"_io.TextIOWrapper",属于装饰类型,许多操作功能都被包装在了一起,该类对象可以进行文件读写
"""
def close(self):关闭文件资源
def fileno(self):获取文件描述符,0(stdin),1(stdout),2(stderr),其他数字(映射打开文件的地址)
def flush(self):强制刷新缓冲区
def read(self, n:int=-1):数据读取,默认读取全部,也可设置读取个数
def readlines(self, hint:int=-1):读取全部数据行,以列表形式返回
def readline(self, limit:int=-1):读取每行数据('\n'结尾),也可设置读取个数
def truncate(self, size:int=None):文件截取
def writable(self):判断文件是否可写
def write(self, s:AnyStr):文件写入
def writelines(self, lines:List[AnyStr]):写入一组数据
"""
#通过with实现所有资源对象的连接与释放
with open("d:\\test.txt", "w") as f:
	f.write("abc")

with open("d:\\test.txt", "r") as f:
	data = f.readline() #读取一行数据(包括'\n')
	while data:
		print(data)
		data = f.readline()
#迭代文件对象,文件对象本身是可迭代的,迭代时以'\n'进行分割
with open("d:\\test.txt", "r") as f:
	for line in f:
		print(line) #输出每行内容

#随机读取
"""
def seek(self, offset:int, whence:int=0):设置文件读取位置标记
offset读取偏移量(字节数),whence:可选,表示从哪个位置开始偏移,0文件开头,1当前位置,2文件末尾
def seekable(self):判断是否可偏移
def tell(self):获取当前文件标记
"""
with open(file="d:\\test.txt", mode="r") as f:
	f.seek(10) #越过开头10个字节,每次都是以文件开始位置为基准进行偏移
	print("当前位置:%s,data:%s" % (f.tell(), f.read(10).strip()))#读取10字节并去除空格,'\n'也占一字节

文件编码

#命令行使用'chcp'查看编码
#字符串定义时提供有encode()方法,若不设置则使用当前系统默认的编码进行转换,转换目标类型为二进制数据,因此接收时必须通过decode()进行解码处理
s = "你好".encode("GBK") #转换后的编码内容为二进制字节数组
print(s.decode("GBK"))

#查看当前编码
import chardet #需要安装
s = "你好".encode()
print(charset.detect(s))

with open(file="d:\\test.txt", mode="w", encoding="UTF-8") as f: #设置文件保存编码
	f.write("abc")

文件缓冲

#在进行文件写入时利用缓冲可以避免频繁的IO资源占用(程序调用cpu的写入指令,数据先保存在内存,保存足够的数据量后再一次性写入到目标终端)
#常规的数据输出没有缓冲,若要提高数据的写入效率则需要进行缓冲的开启
"""
buffering:
全缓冲(当标准IO缓存被填满后才会进行真正的IO操作,如对磁盘文件的读写操作):>1
行缓冲(在IO操作中遇见'\n'时才会进行真正的IO操作,如网络聊天工具中编写文字):==1
不缓冲(直接进行终端设备的IO操作,数据不进行缓冲保存,如程序错误立即进行错误信息显示):0
只有二进制文件可以设为0,文本文件不可以
执行了close()操作后,缓冲的内容会全部进行输出,或进程结束前也会进行程序缓冲的刷新,flush()方法也可以进行缓冲区的强制刷新
"""
f = open(file="d:\\test.txt", mode="w", encoding="UTF-8", buffering=1)
f.write("abc")
# f.write("\n") 刷新缓冲区
f.flush() #强制清空缓冲区

OS模块

#是用于与操作系统进行交互的一个操作模块,提供大量与系统相关的处理函数
"""
os模块提供了一些处理函数,可以直接实现系统的命令操作
getcwd() 获取当前的工作目录
chdir(path) 切换工作目录
system() 执行本地操作系统命令,仅仅是向操作系统发出一个执行指令
popen(cmd, mode='r', buffering=1) 开启一个命令管道,cmd要执行的程序命令,mode操作权限模式('r'或'w'),buffering设置缓冲大小(0无缓冲,1行缓冲,>1全缓冲)
symlink(src, dst) 创建软连接
link(src,dst) 创建硬连接
"""
import os
def main():
    os.chdir("d:/") #切换当前工作目录
    os.system("md test") #windows下执行系统命令,创建目录
    print("当前路径:%s" % os.getcwd())
#linux下:"os.system("killall 程序名")"结束指定进程

#某些执行命令可能会返回相应的数据信息,可使用"os.popen()"获取命令的IO信息
import os
def main():
    fd = os.popen(cmd="echo abc", mode='r', buffering=1)
    val=fd.readline() #读取数据
    while val:
        print(val)
        val = fd.readline()

#软连接(相当于快捷方式)
os.symlink("d:\\test", "d:\\testtmp") #真实路径,软连接路径

os.path子模块

核心作用是进行路径处理操作

#linux使用的路径分隔符:/,windows使用的路径分隔符:\,不同操作系统有差异
import os,datetime,time
PATH = "d:\\test"
def main():
    if os.path.exists(PATH): #判断路径是否存在
        print("绝对路径:%s" % os.path.abspath(PATH))
        print("父路径:%s" % os.path.dirname(PATH))
        print("文件名称:%s" % os.path.basename(PATH))
        print("文件大小:%s" % os.path.getsize(PATH)) #返回字节数据
        print("当前路径是否为文件:%s" % os.path.isfile(PATH))
        print("当前路径是否为目录:%s" % os.path.isdir(PATH))
        #os.path.isabs判断给定路径是否为绝对路径
        #os.path.islink(path) 判断给定路径是否是链接
        #os.path.ismount(path) 判断给定路径是否为挂载点
        #可以针对给定路径进行各种拆分处理以及判断和取得数据信息的功能

        print(os.path.expanduser("~")) #"~"描述得是用户所在的根路径,将路径中包含的"~"替换成用户目录
        print("未格式化路径:%s" % os.path.expanduser("~/t001/t002"))
        print("格式化路径:%s" % os.path.normpath(os.path.expanduser("~/t001/t002")))
        #os.path.join(path1[,path2[,...]]) 路径合并
        #os.path.normcase(path) 规范化给定路径中的大小写和斜杠
        #os.path.realpath(path) 返回给定路径的真实路径
        #os.path.split(path) 将路径分割为dirname和basename元组

        #文件的元数据:如文件大小,创建的日期时间、授权等
        print("文件创建时间:%s" % os.path.getctime(PATH)) #获得的是时间戳
        print("文件创建时间:%s" % datetime.datetime.strptime(time.ctime(os.path.getctime(PATH)), "%a %b %d %H:%M:%S %Y"))
        #getatime(path)返回最近访问时间
        print("最近修改时间:%s" % os.path.getmtime(PATH))
if __name__ == '__main__':
    main()
"""
绝对路径:d:\test
父路径:d:\
文件名称:test
文件大小:0
当前路径是否为文件:False
当前路径是否为目录:True
C:\Users\dell
未格式化路径:C:\Users\dell/t001/t002
格式化路径:C:\Users\dell\t001\t002
文件创建时间:1679486749.5310864
文件创建时间:2023-03-22 20:05:49
最近修改时间:1679486749.5310864
"""

#os.path中提供有路径变量表示路径分隔符、后缀名分隔符等(os中也有与之对应的变量)
#curdir:当前文件夹".",pardir:上一层文件夹".."
import os
PATHA = "d:" + os.path.sep + "test.txt" #sep系统路径分隔符
PATHB = "d:" + os.sep + "test" + os.path.extsep + "txt" #extsep 文件名和后缀之间的间隔符号"."
#os.path.sep与os.sep设置的内容是完全相同的
def main():
    if os.path.samefile(PATHA, PATHB): #判断两路径是否相同是否为同一文件
        print("ok")
    print(PATHA)
    print(PATHB)
"""
ok
d:\test.txt
d:\test.txt
"""
if __name__ == '__main__':
    main()

目录操作

import os
PATHA = "d:" + os.path.sep + "test" + os.sep + "t01" # 目录路径
def list_path(path):
    if os.path.isdir(path):
        try:
        	#listdir列出当前目录中的所有子目录(单级)
            for i in os.listdir(path): #直接"~",是无法识别的
                list_path(os.path.join(path, i)) #路径连接
        except PermissionError as err: #操作系统有些目录拒绝访问
            pass
    else:
        print(path)

def main():
    if not os.path.exists(PATHA):
    	#mkdir(path,mode)创建单级目录
        os.makedirs(PATHA) #创建多级目录,相当于"mkdir -p /目录/目录",makedirs(path, mode=0o777,exist_ok=False)
    else:
    	#remove(path)删除当前目录
        os.removedirs(PATHA) #删除目录
    list_path(os.path.expanduser("~"))

if __name__ == '__main__':
    main()

#os模块中提供有一个walk()函数,可以进行列表的实现,相比于上面简化很多
import os
def main():
    path = os.path.expanduser("~")
    #列出指定目录中的内容结构
    for path,dirnames,filenames in os.walk(path): #返回一个生成器,返回元组的操作内容(3个)
        print("文件路径:%s,子目录列表:%s,子文件列表:%s" % (path,dirnames,filenames))

if __name__ == '__main__':
    main()

#重命名目录
import os
PATH = "d:" + os.path.sep + "test"
PATH_DST = "d:" + os.path.sep + "t01"
def main():
    if os.path.exists(PATH):
        os.rename(PATH, PATH_DST)
    #rename除了进行目录重命名,同时可以进行文件的重命名

授权管理

import os,stat #需要导入stat模块
#linux下
PATH = os.path.sep + "usr" + os.path.sep + "test.txt"
def main():
    if os.path.exists(PATH):
        #修改权限
        if not os.access(PATH, 754): #检测授权模式,是否有指定权限
        	#修改权限,mode可设数值,也可设置如下常量
            os.chmod(PATH, stat.S_IRWXU | stat.S_IXGRP | stat.S_IRGRP | stat.S_IROTH)
            """
        stat.S_IXOTH:其他用户执行权
        stat.S_IWOTH:其他用户写权限
        stat.S_IROTH:其他用户读权限
        stat.S_IRWXO:其他用户全部权限
        stat.S_IXGRP:组用户执行权限
        stat.S_IWGRP:组用户写权限
        stat.S_IRGRP:组用户读权限
        stat.S_IRWXG:组用户全部权限
        stat.S_IXUSR:拥有者执行权限
        stat.S_IWUSR:拥有者写权限
        stat.S_IRUSR:拥有者读权限
        stat.S_IRWXU:拥有者全部权限
        """
        #修改路径拥有者(需要明确知道文件所有者的UID与GID)
        uid = 999
        gid = 1001
        os.chown(PATH, uid, gid)
#fchmod(fd, mode)修改文件权限
#fchown(fd, uid, gid)修改文件所有权
#lchmod(path, mode)修改链接文件权限
#lchown(path, uid, gid)更改链接文件所有者

os模块文件操作

#os模块提供了文件操作的进一步简化
import os
PATH = "d:" + os.sep + "test.txt"

def main():
    fd = os.open(PATH, os.O_RDWR | os.O_CREAT) #获得一个文件对象
    """
    os.O_RDONLY:只读
	os.O_WRONLY:只写
	os.O_RDWR:读写
	os.O_APPEND:追加
	os.O_CREAT:创建并打开一个新文件
	mode参数可选,stat模块中定义的权限描述
    """
    os.write(fd, "abc".encode("UTF-8")) #写数据
    os.lseek(fd, 10, os.SEEK_SET) #字节跨过
    #随机读写,os.SEEK_SET(0,开始位置),os.SEEK_CUR(1,当前位置),os.SEEK_END(2,结尾)
    data = os.read(fd, 12).decode("UTF-8") #读取指定长度数据
    print(data)
    os.close(fd)
#os.dup(fd)复制文件描述符对象

IO功能模块

IO的扩展模块

fileinput模块

#主要进行文件输入的处理操作,对输入的数据处理形式更加方便
import fileinput,os,glob
PATH = "d:\\test.txt"
PATH2 = "d:\\t01" + os.sep + "*.txt"#目录
def main():
    #单一文件读取
    #fileinput.input()函数返回一个直接可迭代对象
    for data in fileinput.input(files=PATH, openhook=fileinput.hook_encoded("UTF-8")):
        #files=None文件加载,读取文件的路径列表
        #inplace=False是否将标准输出的结果写回文件
        #backup=""备份文件的扩展名
        #bufsize=0缓冲区大小
        #mode='r'读写模式
        #openhook=None(设置钩子函数,回调处理):想要encoding编码指派则需要通过openhook的形式来完成
        #
        print(data)
    fileinput.close()

    #读取一个目录或多个文件读取
    print(glob.glob(PATH2)) #通过glob模块实现文件的正则匹配
    for data in fileinput.input(files=glob.glob(PATH2), openhook=fileinput.hook_encoded("UTF-8")):
        print("当前操作的文件名:%s, 已经读取的数据行号(总数据行号):%s, data:%s" 
        % (fileinput.filename(), fileinput.lineno(), data))
        """
        filelineno()返回当前数据所在行号(每个文件读取的行数)
        isfirstline()检查当前是否为文件第一行
        isstdin()判断是否为stdin中读取数据
        """
    fileinput.close()
    
    #使用fileinput.input()进行数据读取时,要将所有要读取的文件路径以列表的形式定义出来,就可以自动进行内容的迭代读取处理了

io模块

传统io操作的延申,主要针对于一些临时文件进行IO操作(会发生IO操作,但不会产生具体的文件,所有IO操作都在内存中处理)

#在io模块中提供有StringIO类实现内存的字符串数据操作,直接在内存中进行数据IO,不会产生文件
import io
def main():
    str_io = io.StringIO() #创建一个内存的字符串操作对象
    str_io.write("abcd\n") #写数据
    print(str_io.getvalue()) #获取所有字符串临时IO中的内容

#以及提供BytesIO类实现内存中二进制字节数据的处理,实现字节的内存流(在内存中利用输入输出进行处理的操作形式)
import io
def main():
    byte_io = io.BytesIO() #创建二进制内存流
    byte_io.write("abcd\n".encode("UTF-8")) #写数据,将字符串转为二进制,bytesIO内跟的是二进制数据而不是字符串,所以需要进行转换
    print(byte_io.getvalue().decode("UTF-8"))
#在整体的处理之中,内存流属于会发生IO,但不会产生痕迹的处理,一般可用于临时的IO环境出现

shutil模块

可以针对文件或目录进行整体复制、移动或删除(复制应采用二进制的形式处理)

import os,shutil
src_path = "d:" + os.sep + "test.png" #文件
dst_path = "d:" + os.sep + "t01.png"
src_path2 = "d:" + os.sep + "test" #目录
dst_path2 = "d:" + os.sep + "t01"
def main():
	shutil.copyfile(src_path, dst_path) #文件拷贝,文件已存在则覆盖
	shutil.copytree(src_path2, dst_path2) #目录拷贝,(还有第三个参数symlinks,为True则保持原目录的符号链接),自动的进行目录的迭代以及子文件的拷贝
	shutil.rmtree(src_path2) #删除目录全部内容
"""
move(src, dst) 文件移动
copymode(src, dst) 复制源文件mode
copystat(src, dst) 复制源文件信息
copy(src, dst) 文件或目录拷贝
"""

pickle模块

# 比较特殊的数据输出,如列表、字典、自定义对象等,需要通过序列化的机制
#所有数据最终保存在内存中,有结构的数据需要按照特定的二进制形式进行存储,这样的数据操作就是序列化,而存储完成的二进制可能保存在文件或进行网络交互,此时就需要反序列化来获取原始二进制的数据内容(即二进制形式转换为原始数据)
import os,pickle
path = "d:" + os.sep + "test"
class test:
    __slots__ = ("__data",)
    def __init__(self, data):
        self.__data = data
    def __str__(self)->repr:
        return self.__data
def main():
    exa = test("abcdef")
    with open(file=path, mode="w+b") as file: #以二进制写入模式打开文件
        pickle.dump(exa, file) #实现对象的序列化操作,将对象序列化的二进制数据保存在文件之中
    #如果想正确的读取二进制内容,需要对字节数据进行反序列化处理
    with open(file=path, mode="r+b") as file: #以二进制写入模式打开文件
        data = pickle.load(file) #反序列化,通过指定的二进制文件反序列化对象
        print(data)
#dumps(obj) 返回序列化后的二进制数据
#loads(bytes_object) 从二进制数据中反序列化对象

CSV模块

csv是一种文件的格式,一般保存多个数据信息的内容,进行数据存储,但每个数据信息都有各自的组成部分(自定义),用这种类型的文件进行数据采集内容的记录
以纯文本文件的形式进行数据记录的存储格式,在csv文件内部使用不同的数据行记录数据内容,每行数据使用特定的符号(一般是逗号)进行数据项的拆分,这样就形成了相对简单且通用的数据格式,实际开发中利用csv数据格式可以方便实现大数据系统中对于数据采集结果的信息记录,也可以方便的进行数据文件的传输,csv文件格式也可以方便的被excel工具所读取(只要在windows下就可自动的和excel进行关联)

#CSV文件内部一般对于不同的数据项使用特定的分隔符(一般是","),除了数据外,CSV文件内部还可以设置一些文件的标题
#写入数据
import csv,os
PATH = "d:" + os.sep + "test.csv"
heads = ["name", "id", "sum"]
def main():
	lists = [['a','1','10'],
			 ['b','2','20'],
			 ['c','3','30']]
	#如果不使用newline(换行符),则会在每行记录之间多出一个空行
	with open(file=PATH, mode="w", newline="", encoding="UTF-8") as f: #使用UTF-8就不能直接使用excel打开,会乱码,可以使用数据导入的形式操作
		csv_f = csv.write(f) #创建csv的写入对象
		csv_f.writerow(heads) #写入头部信息
		for i in range(10): #生成数据
			csv_f.writerow("test%s" % i, i, i)
		#可以将要生成的数据保存在列表中,通过列表迭代进行每组数据的输出,即如果列表是一堆完整数据,可以直接进行列表内容的文件输出
		csv_f.writerows(lists) #直接写入列表数据

#读数据
import csv,os
PATH = "d:" + os.sep + "test.csv"
def main():
	with open(file=PATH, mode="r", newline="", encoding="UTF-8") as f:
		csv_f = csv.reader(f) #创建csv的读取对象
		heads = next(csv_f) #读取标题内容
		print(heads)
		for i in csv_f: #读取后续内容
			print(i)
			
#既然可以直接将列表写入csv文件,就也可以直接将csv文件内容转为列表,但若csv文件过大,则该操作容易引发内存溢出
import csv,os
PATH = "d:" + os.sep + "test.csv"
def main():
	with open(file=PATH, mode="r", newline="", encoding="UTF-8") as f:
		csv_f = csv.reader(f) #创建csv的读取对象
		heads = next(csv_f) #读取标题内容
		print(heads)
		rows = [row for row in csv_f]
		print(rows)
		#一般进行csv文件读取时,都会读取一行处理一行,不会在内存中保存过多的这样的采集数据的内容

#csv与字典操作
#对于标题行可以结合字典形式进行处理(而不是next()空出标题行),将标题行的标题列进行key的定义,而后读取相关内容
import csv,os
PATH = "d:" + os.sep + "test.csv"
heads = ["name", "id", "sum"]
def main():
	dict_lists = [
		{"name":"a", "id":"1", "sum":"10"},
		{"name":"b", "id":"2", "sum":"20"},
		{"name":"c", "id":"3", "sum":"30"}
	]#字典中的key对应了标题行
	with open(file=PATH, mode="w", newline="", encoding="UTF-8") as f:
		csv_f = csv.DictWriter(f, heads) #字典写入,设置标题,未写入
		csv_f.writeheader() #写入标题
		csv_f.writerows(dict_lists) #写入多行数据
	#字典形式读取csv数据
	with open(file=PATH, mode="r", newline="", encoding="UTF-8") as f:
		csv_f = csv.DictReader(f) #字典读取
		for row in csv_f: #迭代读取
			print(row.get("name"), row.get("id"), row.get("sum")) #根据标题读取
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值