序列 (sequence)是Python最基本的一种数据结构。
序列中的每个元素都有编号,即其位置或索引,其中第一个元素的索引为0,第二个元素的索引为1,依此类推。Python的序列索引支持负数,-1表示序列的最后一个元素,这是Python不同其他很多种语言不同的地方。
Python内置了多种序列,列表、元组、字符串是其中最常用的三种,本文为你描述各种序列的通用 *** 作。
索引从0开始,索引号为0的元素为1,greeting的索引号为0的元素为'H'。
你可能注意到'Hello'和'H'都用单引号包围,这是Python不同于其他语言的另一个地方。Python并没有专门用于表示字符的数据类型,因此一个字符就是一个只包含一个元素的字符串。
Python的序列索引支持负数,-1表示倒数第一个元素。
切片 (slicing) *** 作用于访问序列特定 范围 内的元素。在一对方括号内使用两个索引,并用冒号隔开:
注意到,返回的序列并未包含愿序列的第6个元素7,就相当于数学集合中的 左闭右开区间 *** 作。
换言之,你提供两个索引来指定切片的边界,其中第一个索引指定的元素包含在切片内,但第二个索引指定的元素不包含在切片内。
保留冒号,省略羡运备第一个索引,表示从序列起始位置开始切片;省略第二个索引,表示切片到序列末尾,包含最后一个元素:
这个 *** 作的效果是:在指定的区间内间隔取元素,语法格式为:
例如:
步长为正数时,它从起点移到终点,而步长为负数时,它从终点移到起点。
可以使用加法运算(+运算符)拼接两个序列:
从错误消息兄毁可知,不能拼接列表和字符串,虽然它们都是序列。一般而言,不悄配能拼接不同类型的序列。
将序列与数x 相乘时,将重复这个序列x 次来创建一个新序列:
初始化一个长度为10的空列表:
成员资格检查判定一个元素是否存在于集合中,如存在返回True,否则返回False,实际上是一个布尔表达式。
语法:
例如:
内置函数 len 返回序列包含的元素个数,而 min 和 max 分别返回序列中最小和最大的元素。
Python通用的序列 *** 作有:索引、切片、乘法、成员资格检查、长度、最小值和最大值。
在实际处理数据时,因系统内存有限,我们不可能一次把所有数据都导出进行 *** 作,所以需要批量导出依次 *** 作。为了加快运行,我们会采用多线程的方法进行数据处理, 以下为我总结的多线程批量处理数据的模板:
主要分为三大部分:
共分4部分对多线程的内容进行总结。
先为大家介绍线程的相关概念:
在飞车程序中,如果没有多线程,我们就不能一边听歌一边玩飞车,听歌与玩 游戏 不能并行;在使用多线程后,我们就可以在玩 游戏 的同时听背景音乐。在这个例子中启动飞车程序就是一个进程,玩 游戏 和听音乐是两个线程。
Python 提供了 threading 模块来实现多线程:
因为新建线程系统需要分配资源、终止线程系统需要回收资源,所以如果可以重用线程,则可以减去新建/终止的开销以提升性能。同时,使用线程池的语法比自己新建线程执行线程更加简洁握察。
Python 为我们提供了 ThreadPoolExecutor 来实现线程池,此线程池默认子线程守护。它的适应场景为突发性大量请求或需要大量线程完成任务,但实际任务处理时间较短。
其中 max_workers 为线程池中的线程个数,常用的遍历方法有 map 和 submit+as_completed 。根据业务场景的不同,若我们需要输出结果按遍历顺序返回,我们就用 map 方法,若想谁先悔唤完成就返回谁,我们就用 submit+as_complete 方法。
我们把一个时间段内只允许一个线程使用的资源称为临界资源,对临界资源的访问,必须互斥的进行。互斥,也称间接制约关系。线程互斥指当一个线程访问某临界资源时,另一个想要访问该临界资源的线程必须等待。当前访问临界资源的线程访问结束,释放该资源之后,另一个线程才能去访问临界资源。锁的功能就是实现线程互斥。
我把线程互斥比作厕所包间上大号的过程,因为包间里只有一个坑,所以只允许一个人进行大号。当第一个人要上厕所时,会将门上上锁,这时如果第二个人也想大号,那就必须等第一个人上完,将锁解开后才能进行,在这期间第二个人就只能在门外等着。这个过程与代码中使用锁的原理如出一辙,这里的坑就是临界资源。 Python 的 threading 模块引入了锁。 threading 模块提供了 Lock 类,它有如下方法加锁和释放锁:
我们会发现这个程序只会打印“第一道锁”,而且程序既没有终止,也没有继续运行。这是因为 Lock 锁在同一线程内第一次加锁之后还没有释放时,就进行了第二次 acquire 请求,导致无法执行 release ,所以锁永远无法释放,这就是死锁。如果我们使用 RLock 就能正常运行,不会发生死锁的状态。
在主线程中定义 Lock 锁,然后上锁,再创建一个子 线程t 运行 main 函数释放锁,结段前茄果正常输出,说明主线程上的锁,可由子线程解锁。
如果把上面的锁改为 RLock 则报错。在实际中设计程序时,我们会将每个功能分别封装成一个函数,每个函数中都可能会有临界区域,所以就需要用到 RLock 。
一句话总结就是 Lock 不能套娃, RLock 可以套娃; Lock 可以由其他线程中的锁进行 *** 作, RLock 只能由本线程进行 *** 作。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)