HiKariのTechLab

光の技术屋


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 站点地图

  • 搜索

【Hard Python】【第四章-日志】2、日志消费者Handler的实现

发表于 2022-04-16 | 更新于 2024-04-07 | 分类于 Hard Python

在上篇文章里说完了日志实例Logger和日志管理Manager,现在该提到Handler了。Handler是日志信息的消费者,单个Logger实例注册多个Handler,每生成一个LogRecord,就会被合法的Handler消费,在不同地方打印出日志信息。

要研究Handler,首先需要看下基类的实现:

1
2
3
4
5
6
7
8
9
10
class Handler(Filterer):
def handle(self, record):
rv = self.filter(record)
if rv:
self.acquire()
try:
self.emit(record)
finally:
self.release()
return rv

Handler会通过自带的重入锁限制日志记录被串行处理。Handler也是继承Filterer,首先会通过filter过滤日志是否满足Handler的要求,如果合法,然后调用emit方法处理日志。

emit方法在基类是NotImplemented,需要子类加以实现。因此接下来我们具体抽几个例子来看。

阅读全文 »

【Hard Python】【第四章-日志】1、Logger与Manager的源码实现

发表于 2022-04-09 | 更新于 2024-04-07 | 分类于 Hard Python

python语言内置了一个强大的日志模块logging,也是python内部最为复杂的功能模块之一,通过这个模块我们能够实现不同样式的日志打印。关于logging模块的官方文档也非常完备:

  • logging的用法
    • 日志常用指引
    • 日志操作手册
  • logging API
    • logging日志记录工具
    • logging config
    • logging handlers

为此,本文起我们对python的logging模块进行深入剖析,从而让大家能够更好地掌握python的logging模块。

阅读全文 »

【测试人生】用行为树做游戏自动化测试的误区

发表于 2022-04-03 | 更新于 2024-04-07 | 分类于 测试人生

在游戏自动化测试领域,行为树由于其强大的描述玩家(Agent)行为逻辑的功能,在很多场景的自动化测试都能得到应用。但是,如果对行为树的作用认识不足,很容易导致整一个自动化测试项目出现难以维护的窘境。因此,这篇文章谈一谈在游戏自动化测试里,用行为树做测试的一些误区。

阅读全文 »

【Hard Python】【第三章-GC】2、python的GC流程

发表于 2022-03-19 | 更新于 2024-04-07 | 分类于 Hard Python

除了通过引用计数直接销毁对象之外,python还是拥有内在GC机制的,并且也有完整的一套流程。

如果只有通过引用计数销毁对象这种机制,那么随便构造一个循环引用就会造成内存泄漏,比如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def _dump_gc():
gcobjs = gc.get_objects()
pprint.pprint(len(gcobjs))


def test_circle():
def _test_internal():
_dump_gc()
a = []
b = []
a.append(b)
b.append(a)
_dump_gc()

_test_internal()
_dump_gc()
gc.collect()
_dump_gc()

打印出来的结果是:

1
2
3
4
13707
13709
13709
13370

很显然,当退出_test_internal作用域时,gc对象的数量没有变化,这就说明在_test_internal里创建的a、b两个对象没有被立即释放掉。如果注释掉两个append行,就能看到打印结果第三行变成了13707,说明a、b在退出函数时就被销毁了。

所以首先,我们从循环引用入手,来研究一下python的gc机制(好巧不巧的是,python的gc也是专门为循环引用而设置的)。调用gc.collect触发gc之后,会跑到gc_collect_main触发完整的gc流程。gc_collect_main是python整个gc流程的主入口,我们来看其中的代码:

阅读全文 »

【Hard Python】【第三章-GC】1、引用计数与内存释放机制

发表于 2022-03-12 | 更新于 2025-07-06 | 分类于 Hard Python

对于编程语言runtime来说,建立起良好运转GC机制是非常必要的,像Java和Go,其GC机制都经历了复杂的演化,当然同时也为编程语言带来了更好的性能,这也是为什么这两门语言能成为主流服务端语言的原因之一。

相对于Java和Go,python的GC机制是相对简约的,其中最基础的机制之一就是引用计数。当对象生成时引用计数为1;对象被其它对象引用时引用计数增加1;对象没有被引用,又退出作用域的话,引用计数归0;引用计数归0后,对象被销毁。

我们可以通过一个例子对引用计数机制进行研究:

1
2
3
def test_ref():
a = '123456789123456789'
del a

其反编译的结果是:

阅读全文 »

【Hard Python】【第二章-异步IO】3、async/await的源码实现

发表于 2022-02-26 | 更新于 2024-04-07 | 分类于 Hard Python

说完了asyncio事件循环是如何运行异步任务的,接下来back to basic,我们一起看看async和await两个原语具体代表了什么含义。

首先是async,async通常用来修饰一个函数,表示这个函数会返回一个协程。比如说:

1
2
3
4
5
6
7
async def _coro_maker(i):
print(i + 1)


def test_async():
c = _coro_maker(1)
asyncio.run(c)

对_coro_maker进行反编译,得到这样的结果:

阅读全文 »

【Hard Python】【第二章-异步IO】2、异步任务在事件循环中的执行

发表于 2022-02-20 | 更新于 2024-04-07 | 分类于 Hard Python

接续第一话的内容,事件循环在创建之后,又是如何运行协程任务以及异步IO任务的?
​
由asyncio.run的代码可知,loop.run_until_complete是运行协程的方法。其定义如下:

阅读全文 »

【Hard Python】【第二章-异步IO】1、asyncio事件循环的创建

发表于 2022-02-12 | 更新于 2024-04-07 | 分类于 Hard Python

python3中增加的重要特性之一即为asyncio,其提供了异步编程的原语支持,从而能够让python在事件驱动、协程协同等方面的编程场景大杀四方。

事件循环EventLoop是异步编程中的核心概念之一。python的异步IO,就从事件循环的实现开始讲起。

首先看一段示例代码:

1
2
3
4
5
6
7
8
9
async def _test_run_main():
for i in range(3):
await asyncio.sleep(1)
print(f'[test_run] {i}')


def test_run():
coro = _test_run_main()
asyncio.run(coro)

通过async def定义的函数,其返回值是一个异步协程coroutine。协程相当于是事件循环里的一个单位任务,通过asyncio.run接口就可以将其运行起来。因此我们先来看asyncio.run的实现:

阅读全文 »

【Hard Python】【第一章-多进程】3、Pool,多任务并行进程池

发表于 2022-01-30 | 更新于 2024-04-07 | 分类于 Hard Python

前面讲了进程创建与进程通信的内容,接下来讲一下多进程编程最能发挥的地方。对于同时运行多个同质任务来讲,采用multiprocessing.Pool进程池去管理是最方便的。Pool的用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from multiprocessing import Pool, process
import os
import pprint


def _test_func(a, b):
result = a + b
print(f'{os.getpid()}: {result}')
return result


def test_pool():
test_data = [(2 * i, 2 * i + 1) for i in range(16)]
with Pool(4) as p:
pprint.pprint(process.active_children())
results = p.starmap(_test_func, test_data) # starmap指iterable的unpack,*args这样,详情看源码注释
print(f'{os.getpid()}: {results}') # 得到_test_func的所有结果


if __name__ == '__main__':
test_pool()

打印出来的结果,可能是这样子的:

阅读全文 »

【Hard Python】【第一章-多进程】2、Pipe和Queue,进程间通信

发表于 2022-01-22 | 更新于 2024-11-03 | 分类于 Hard Python

第一话详细讲解了Process新进程是如何被创建的,接下来就来讲一下进程之间有什么通信的方法。

要在multiprocessing中实现进程间通信,最直接的方法是采用Pipe或者Queue。其用法如下:

阅读全文 »
1…91011…20
ひかり.HDQ

ひかり.HDQ

talk is cheap, code is rich
195 日志
14 分类
417 标签
GitHub Mail CSDN Juejin Steam Bilibili
© 2019 – 2025 ひかり.HDQ
|