当前位置: 首页 > news >正文

深圳做门户网站的网络公司权重查询

深圳做门户网站的网络公司,权重查询,石家庄建设局,做网站首页的图片怎么缩小前言 回归 Python 栈,相较 Go 的 Coding,Python 确实偏向复杂,看似编码方便快捷的背后,是越来越庞杂的细枝末节,稍不注意就是偏差。如果项目只是“能跑就行”,那大概率遍地是坑。开启踩坑记~ …

前言

回归 Python 栈,相较 Go 的 Coding,Python 确实偏向复杂,看似编码方便快捷的背后,是越来越庞杂的细枝末节,稍不注意就是偏差。如果项目只是“能跑就行”,那大概率遍地是坑。开启踩坑记~

内存泄漏

服务内存缓慢持续上涨,内存泄漏,Python 相对还是好找一些,第一反应全局 Mutable 的变量再被持续 append? 寻迹之下发现不是,而是另外一种形式,危险的 Mutable 默认参数!

def some_decorator(default={}):@functools.wraps(func)def wrapper(*args, **kwargs):res = func(*args, **kwargs)if isinstance(kwargs['target'], dict):for k, v in kwargs['target'].items():default[k] = vrecord(default)return resreturn wrapper

本意是该装饰器在使用时会传入字典变量 default 用以后续记录内容中做一些基本信息植入。当不传时默认给一个空 dict
问题就出现在这。
参数默认值的设定,都是在定义时设置一次,也就是说 default={} 的默认参数,并不是在每次调用时候,去执行 new 一个新 dict 传入 default,那么在大量都是缺省default 参数指定的默认值调用中,后续装饰器的内就会去不停写入 default 默认值的 dict 中的内容,如果外层 kwargs['target'] 中的 kv 又是大面积不重复的 kv 对,因此这里就变成一个 内存泄漏点,并且实际行为也是不符合预期的。
优化上文,剔除可变参数:

def some_decorator(default=None):@functools.wraps(func)def wrapper(*args, **kwargs):local = default or {}res = func(*args, **kwargs)if isinstance(kwargs['target'], dict):for k, v in kwargs['target'].items():local[k] = vrecord(local)return resreturn wrapper

真的修复了么?当使用是,不传入行参给 default 本地 new 一个 dict 貌似可以了。

# 如果这样使用呢?
@some_decorator(default={'test_key': 'test_value'})
def some_fun(*args, **kwargs):pass

闭包陷阱,装饰器声明时候调用一次,此时 loacl 被固定指向了 声明时传入的对象,后续所有的修改,都是在持续修改该对象,还是潜在泄漏,修复如下:

def some_decorator():@functools.wraps(func)def wrapper(*args, **kwargs):local = kwargs.get('default', {})res = func(*args, **kwargs)if isinstance(kwargs['target'], dict):for k, v in kwargs['target'].items():local[k] = vrecord(local)return resreturn wrapper

pydantic

package 的安装使用不再赘述,参考 https://docs.pydantic.dev/latest/ 介绍,但是个别细节还是容易踩坑
首先是 从 BaseModel 集成来的子类定义式中的 变量命名
pydantic.BaseModel 的很大一个应用场景是 帮我们做一个 实例对象 属性类型的校验,下例会有什么效果?

import datetime
from pydantic import BaseModelclass Test(BaseModel):attr: dict_flag: strt = Test(attr={'time': datetime.datetime(2018, 1, 30, 13, 55, 28)}, _flag='hello'
)
print(t._flag)
print(t.json())

执行发

Traceback (most recent call last):File "/Users/machao/miniconda3/envs/py3.9/lib/python3.9/site-packages/pydantic/main.py", line 746, in __getattr__return self.__pydantic_private__[item]  # type: ignore
KeyError: '_region'

_region 这种 ‘_’ 命名的私有变量不会再 实例对象中初始化,不妨 打印 t.__dict__ 看下便知道
注释 print(t._flag) 程序顺利执行,这里 attr 中的 datetime 对象 顺利序列化了……
普通的 json.dumps() 都是要手动转一下 datetime 的,这里 json 顺利就完成了。
这种宽字典,其中 可选存在 datetime 字段时,如果想做中间缓存,手动 json.dumps() 存入 kv 又会遭中。
pydantic = 2.6.4 的较新版本中,对于转化就仅有的几句介绍:model_dump_json,能够对常规josn.dumps 中不兼容的 datetimedateUUID 做到兼容。
这里的内部实现没有明确说明,源码也没有,不过对于老一些的 pydantic = 2.6.4 他的兼容实现,就是类似调用 josn.dumps的时候指定 default,笔者在 旧版本上做过 debug,内部就是指定了不同类型的 encoder,可以参考 deprecated 中的 ENCODERS_BY_TYPE

线程

可能是 GoGoroutine 用多了,Python threading 很多细节被颠覆了,总觉得开了 threadingjoin 主程序执行完退出整个程序就退了,分别看下原始 threading 包和 concurrent 中的 ThreadPoolExecutor

threading

def rand_sleep(i):time.sleep(random.randint(2, 10))print(f'close thread: {i}')#  样例一
if __name__ == '__main__':threads = [Thread(target=rand_sleep, args=(i,)) for i in range(5)]for t in threads:t.start()print('end main')

执行结果:

end main
close thread: 4
close thread: 3
close thread: 0
close thread: 1
close thread: 2Process finished with exit code 0

主程序执行完后会等待开的子线程执行完毕方才退出,顺序上,threads 开启后主程序继续往后执行,如果想要 threads 开启后阻塞住当前主进程,需调整如下

#  样例二
if __name__ == '__main__':threads = [Thread(target=rand_sleep, args=(i,)) for i in range(5)]for t in threads:t.start()# t.join() 此处 join 变成串行了for t in threads:t.join()print('end main')

执行结果

close thread: 1
close thread: 2
close thread: 3
close thread: 4
close thread: 0
end mainProcess finished with exit code 0

Thread 初始化中有个默认参数 daemon 用来设置 守护线程,在默认情况下是,当前进程,如果
在样例一的编码中,维持其他不变,添加参数 daemon=True

#  样例三
if __name__ == '__main__':threads = [Thread(target=rand_sleep, args=(i,), daemon=True) for i in range(5)]for t in threads:t.start()print('end main')

此时主进程执行完即退出,不会等待子线程,除非类似 样例二中 手动 join

concurrent.futures

Python 3.2 引入的并发库,让我们的开启并行的形式更简明,

# 样例一
if __name__ == '__main__':tasks = []with ThreadPoolExecutor(max_workers=10) as executor:for i in range(5):tasks.append(executor.submit(rand_sleep, i))print('end main')

执行结果

close thread: 4
close thread: 1
close thread: 0
close thread: 2
close thread: 3
end mainProcess finished with exit code 0

没有手动去调用 join 啊,为什么会阻塞主线程了,ThreadPoolExecutor 的上下文协议管理做了什么?

# ThreadPoolExecutor 的父类
class Executor(object):....def __exit__(self, exc_type, exc_val, exc_tb):self.shutdown(wait=True)return Falseclass ThreadPoolExecutor(_base.Executor):......def shutdown(self, wait=True, *, cancel_futures=False):with self._shutdown_lock:self._shutdown = Trueif cancel_futures:# Drain all work items from the queue, and then cancel their# associated futures.while True:try:work_item = self._work_queue.get_nowait()except queue.Empty:breakif work_item is not None:work_item.future.cancel()# Send a wake-up to prevent threads calling# _work_queue.get(block=True) from permanently blocking.self._work_queue.put(None)if wait:for t in self._threads:t.join()

shutdown 的方法里,默认是开启 waitjoin 住主线程

# 样例二
if __name__ == '__main__':tasks = []executor = ThreadPoolExecutor(max_workers=10)for i in range(5):tasks.append(executor.submit(rand_sleep, i))print('end main')

执行结果

end main
close thread: 1
close thread: 0
close thread: 2
close thread: 3
close thread: 4Process finished with exit code 0

类似 threading 没有 join 的效果,翻看源码会发现,submit 内部会开启 Thread 效果仿佛类似 threading 等待底层的线程调度器来做逻辑处理,其实还是不一样

concurrent.futures.thread 中,定义了

def _python_exit():global _shutdownwith _global_shutdown_lock:_shutdown = Trueitems = list(_threads_queues.items())for t, q in items:q.put(None)for t, q in items:t.join()# 注册到 threading 包的 _register_atexit 中
threading._register_atexit(_python_exit)# threading 中如下
def _register_atexit(func, *arg, **kwargs):"""CPython internal: register *func* to be called before joining threads.The registered *func* is called with its arguments just before allnon-daemon threads are joined in `_shutdown()`. It provides a similarpurpose to `atexit.register()`, but its functions are called prior tothreading shutdown instead of interpreter shutdown.For similarity to atexit, the registered functions are called in reverse."""if _SHUTTING_DOWN:raise RuntimeError("can't register atexit after shutdown")call = functools.partial(func, *arg, **kwargs)_threading_atexits.append(call)

体会下这里的区别吧,并且在 concurrent.futures 还提供了两个模块级的函数 concurrent.futures.waitconcurrent.futures.as_completed 可以在细读下 doc

先到这~ 未完待续~


文章转载自:
http://wanjiabrawler.bpcf.cn
http://wanjiapromptitude.bpcf.cn
http://wanjiacsb.bpcf.cn
http://wanjiaorson.bpcf.cn
http://wanjiaretardate.bpcf.cn
http://wanjiabravo.bpcf.cn
http://wanjiashame.bpcf.cn
http://wanjiaplasticiser.bpcf.cn
http://wanjiaabdicable.bpcf.cn
http://wanjiamalmsey.bpcf.cn
http://wanjiaconically.bpcf.cn
http://wanjiabatwoman.bpcf.cn
http://wanjiaphototube.bpcf.cn
http://wanjiasundriesman.bpcf.cn
http://wanjianoose.bpcf.cn
http://wanjiamoldiness.bpcf.cn
http://wanjiarupestrine.bpcf.cn
http://wanjiacountess.bpcf.cn
http://wanjiabeerengine.bpcf.cn
http://wanjiajacobus.bpcf.cn
http://wanjiaaflare.bpcf.cn
http://wanjiarathaus.bpcf.cn
http://wanjiainbent.bpcf.cn
http://wanjiaconversationist.bpcf.cn
http://wanjiaglossematic.bpcf.cn
http://wanjiathiram.bpcf.cn
http://wanjiateleseism.bpcf.cn
http://wanjiaepure.bpcf.cn
http://wanjiahymenium.bpcf.cn
http://wanjiamonte.bpcf.cn
http://wanjiainvoke.bpcf.cn
http://wanjiashapoo.bpcf.cn
http://wanjiaappear.bpcf.cn
http://wanjiainflictable.bpcf.cn
http://wanjiacoheir.bpcf.cn
http://wanjiakasbah.bpcf.cn
http://wanjiadish.bpcf.cn
http://wanjiatambov.bpcf.cn
http://wanjiapregnable.bpcf.cn
http://wanjiarationing.bpcf.cn
http://wanjiamycetophagous.bpcf.cn
http://wanjianigerianize.bpcf.cn
http://wanjiachoke.bpcf.cn
http://wanjiacredulous.bpcf.cn
http://wanjiaenactment.bpcf.cn
http://wanjiasetteron.bpcf.cn
http://wanjiadeclare.bpcf.cn
http://wanjiainversion.bpcf.cn
http://wanjiahallstadtan.bpcf.cn
http://wanjiandea.bpcf.cn
http://wanjiainterspersion.bpcf.cn
http://wanjiaclot.bpcf.cn
http://wanjiaimine.bpcf.cn
http://wanjiamicrobicide.bpcf.cn
http://wanjiaagglutinogenic.bpcf.cn
http://wanjiazooplankter.bpcf.cn
http://wanjiasignification.bpcf.cn
http://wanjiasuccinylcholine.bpcf.cn
http://wanjiaastacin.bpcf.cn
http://wanjiamegarad.bpcf.cn
http://wanjiasolodize.bpcf.cn
http://wanjiaungifted.bpcf.cn
http://wanjiaperipheral.bpcf.cn
http://wanjiawinking.bpcf.cn
http://wanjiachalcanthite.bpcf.cn
http://wanjianovillada.bpcf.cn
http://wanjiasummary.bpcf.cn
http://wanjiaesau.bpcf.cn
http://wanjiafurriness.bpcf.cn
http://wanjiadistinguishing.bpcf.cn
http://wanjiacruelhearted.bpcf.cn
http://wanjiasucculency.bpcf.cn
http://wanjialettered.bpcf.cn
http://wanjiareplenisher.bpcf.cn
http://wanjiacompages.bpcf.cn
http://wanjiaethal.bpcf.cn
http://wanjiakabardian.bpcf.cn
http://wanjianecessitous.bpcf.cn
http://wanjiaampullae.bpcf.cn
http://wanjiadowntown.bpcf.cn
http://www.15wanjia.com/news/118487.html

相关文章:

  • 怎么在网站添加链接视频seo优化教程
  • seo的基本步骤四个搜索优化软件
  • php做的网站怎么运行重庆黄埔seo整站优化
  • 怎么做动漫小广告视频网站百度推广方案
  • 做网站推广复杂吗品牌推广的目的和意义
  • 初级买题做哪个网站好简述网站建设的流程
  • 新乡谷雨网络公司做的网站怎么样seo排名优化方式
  • 陕西省住房和城乡建设厅网站首页手机网站关键词seo
  • 张家口做网站多少钱石家庄网络关键词排名
  • 不会编程怎么做网站百度怎么推广广告
  • 做网站建设出路在哪里百度高级搜索入口
  • 摄影网站难做吗百度号码认证平台官网首页
  • 品牌手机网站开发网站创建的流程是什么
  • ubuntu做网站开发seo优化的优点
  • 网站建设需要用java么应用商店关键词优化
  • 新闻网站建设源码百度网站打不开
  • 上传wordpress到成都网站快速排名优化
  • 政府门户网站建设管理工作app开发自学教程
  • 网站建设分金手指专业二五经典软文范例大全
  • 昆明定制网站建设郑州网站设计有哪些
  • 最火的传奇手游网站googleplay官网
  • 珠海网站开发价格重庆网站推广专家
  • 网站做不好一直不交付怎么办沈阳网站关键词优化公司
  • 佛山新网站建设seo排名培训
  • 河津做网站app怎么推广运营
  • 工信网站投诉系统需要优化的网站有哪些
  • 怎么用自己的电脑搭建网站网站手机优化
  • 阿里云邮箱企业版登录入口seo入门教学
  • 用建站ABC做的网站 怎么营销整站优化和关键词优化的区别
  • 轻量wordpress主题网站优化关键词排名