vthread中包含两个类:

vthread.vthread.pool

vthread.vthread.thread

其中class pool的原型如下:

class pool(builtins.object)
pool(pool_num=None, gqueue=0, join=False, log=True, monitor=True)

class thread的原型如下:

class thread(builtins.object)
thread(num=1, join=False, log=True)

init:

__init__(self, pool_num=None, gqueue=0, join=False, log=True, monitor=True)
# :pool_num 伺服线程数量
# :gqueue 全局队列表的index,默认0,建议用数字标识
# :join 多线程是否join
# :log print函数的输出时是否加入线程名作前缀

其他:

Class methods defined here:
change_thread_num(num, gqueue=0) from builtins.type
#通过组名字,用来修改线程数量的函数,默认修改gqueue=0的组
# 是静态函数,你可以直接用 vthread.self.change_thread_num(3)修改
# 就是简单的多退少补,用来动态修改伺服线程数量的。
# 因为原理是向线程队列注入停止标记,线程执行和线程接收停止信号是互斥安全的
# 也是在设计初对任务执行完整性的一种考虑 close_all() from builtins.type
# 关闭所有伺服线程 close_by_gqueue(gqueue=0) from builtins.type
# 通过组名关闭该组所有的伺服线程
# 默认关闭gqueue=0组的所有伺服线程 main_monitor() from builtins.type
# 对主线程进行监视的函数
# 一旦主线程执行完毕就会向所有线程池函数队列尾注入停止标记
# 使所有的线程在执行完任务后都停止下来
# 对于命令行使用的 python 脚本尤为重要
# 因为如果所有线程不停止的话,控制权就不会交还给命令窗口;
# 在任意被含有该函数的装饰类装饰的情况下,这个是默认被打开的
# 可以在装饰时通过设置 monitor 参数是否打开,默认以第一个装饰器设置为准 show() from builtins.type
# 简单的打印一下当前的线程池的组数
# 以及打印每一组线程池的线程数量 __dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)
__call__(self, func)
# 类装饰器入口 atom(func)
# 对任意函数进行原子包装(加锁) patch_print()
# print 补丁函数
# monkey patch 式的修改
# 对python内建 print 函数进行加锁
# 使其在调试阶段能更方便使用 toggle(toggle=False, name='thread')
# 开关显示方式,目前提供修改的参数有三个:
# 1. "thread" # 是否在print时在最左显示线程名字
# 2. "error" # 是否显示error信息 unpatch_all(can_be_repatch=False)
# 去补丁函数
# :can_be_repatch=False
# 因为设计是在每次装饰时就会默认patch一次
# 卸载后不可被重新patch的参数添加就是为了
# 可以使得在头部执行这个函数后后面的装饰都不会再patch

example1:多线程

 1 import vthread
2 import time
3 # vthread.thread
4 #========#
5 # 多线程 #
6 #========#
7 # eg.1
8 #普通的多线程装饰器
9 @vthread.thread(3) # 只要这一行就能让函数变成开3个线程执行同个函数
10 def foolfunc(num): #将foolfunc变成动态开启3个线程执行的函数
11 time.sleep(1)
12 print(f"foolstring, test1 foolnumb: {num} @",time.time())
13 #默认参数:join=False;log=True
14 foolfunc(123) # 加入装饰器后,这个函数就变成了开3个线程执行的函数了

执行的结果如下所示:

[   Thread-3  ] foolstring, test1 foolnumb: 123 @ 1585216798.0833788
[ Thread-2 ] foolstring, test1 foolnumb: 123 @ 1585216798.0833788
[ Thread-1 ] foolstring, test1 foolnumb: 123 @ 1585216798.0833788

example2:多线程

 1 import vthread
2 import time
3 # eg.2
4 #为了和pool的使用方法共通(一次函数执行只是一次函数单独执行的效果)
5 # 为了使函数执行更独立可以用 vthread.thread(1) 来装饰
6 # 但是为了使用更为简便 这里的 vthread.thread 等同于 vthread.thread(1)
7
8 #通过装饰函数,将foolfunc变成开启新线程执行的函数
9 @vthread.thread
10 def foolfunc(num):
11 time.sleep(1)
12 print(f"foolstring, test1 foolnumb: {num} @",time.time())
13
14 for i in range(5):
15 foolfunc(123) # 执行与数量分离,可以使得参数传递更为动态
16 # 每次执行都会开启新线程,默认不join。
17 # 注意:
18 # 这种本身就用于简单测试的方法不要将带参数和不带参数的thread装饰器混用!
19 # 可能会造成装饰出现问题。

执行的结果如下:

[   Thread-1  ] foolstring, test1 foolnumb: 123 @ 1585216957.6751187
[ Thread-5 ] foolstring, test1 foolnumb: 123 @ 1585216957.6761105
[ Thread-4 ] foolstring, test1 foolnumb: 123 @ 1585216957.6761105
[ Thread-3 ] foolstring, test1 foolnumb: 123 @ 1585216957.6761105
[ Thread-2 ] foolstring, test1 foolnumb: 123 @ 1585216957.6761105

example3:线程池

 1 import vthread
2 import time
3 # vthread.pool
4 #========#
5 # 线程池 #
6 #========#
7 # 线程池的多线程装饰,对代码入侵较小
8
9 @vthread.pool(3) # 只用加这一行就能实现3条线程池的包装
10 def foolfunc(num):
11 time.sleep(1)
12 print(f"foolstring, test2 foolnumb: {num} @",time.time())
13 # 默认参数:pool_num=None,join=False,log=True,gqueue=0
14 # pool_num不选时就自动选 cpu 核心数
15 # 就是说,装饰方法还可以更简化为 @vthread.pool()
16 # join参数不建议在主线程内打开。
17
18 for i in range(5):
19 foolfunc(i) # 加入装饰器后,这个函数变成往伺服线程队列里塞原函数的函数了
20
21 # 这里的函数执行都是放在伺服线程中执行。
22 # 如果不指定 gqueue 参数,默认是共用0号队列
23 # 不指定 gqueue 参数给多个函数装饰的情况下,用的都是一组伺服线程
24 #可以尝试用gqueue的参数来实现不同函数不同作用域,开启多组伺服线程
25
26 # 不加装饰就是普通的单线程
27 # 只用加一行就能不破坏原来的结构直接实现线程池操作,能进行参数传递

执行的结果如下所示:

[  Thread-1_0 ] foolstring, test2 foolnumb: 1 @ 1585217724.2185104
[ Thread-2_0 ] foolstring, test2 foolnumb: 2 @ 1585217724.2187068
[ Thread-3_0 ] foolstring, test2 foolnumb: 0 @ 1585217724.2187068
[ Thread-1_0 ] foolstring, test2 foolnumb: 3 @ 1585217725.219437
[ Thread-2_0 ] foolstring, test2 foolnumb: 4 @ 1585217725.2204554

可以看出,多线程并发控制的实现可以通过vthread.pool线程池实现

example4:多组线程池

 1 import vthread
2 import time
3 # vthread.pool
4 #==============#
5 # 多组的线程池 #
6 #==============#
7 pool_1 = vthread.pool(2,gqueue=1) # 开2个伺服线程,组名为1
8 pool_2 = vthread.pool(2,gqueue=2) # 开2个伺服线程,组名为2
9
10 @pool_1
11 def foolfunc1(num):
12 time.sleep(1)
13 print(f"foolstring1, test3 foolnumb1:{num} @",time.time())
14
15 @pool_2 # foolfunc2 和 foolfunc3 用gqueue=2的线程池
16 def foolfunc2(num):
17 time.sleep(1)
18 print(f"foolstring2, test3 foolnumb2:{num} @",time.time())
19 @pool_2 # foolfunc2 和 foolfunc3 用gqueue=2的线程池
20 def foolfunc3(num):
21 time.sleep(1)
22 print(f"foolstring3, test3 foolnumb3:{num} @",time.time())
23
24 for i in range(3): foolfunc1(i)
25 for i in range(2): foolfunc2(i)
26 for i in range(1): foolfunc3(i)
27 # 额外开启线程池组的话最好不要用gqueue=0
28 # 因为gqueue=0就是默认参数

执行的结果如下所示:

[  Thread-4_2 ] foolstring2, test3 foolnumb2:1 @ 1585218328.066928
[ Thread-1_1 ] foolstring1, test3 foolnumb1:0 @ 1585218328.066928
[ Thread-3_2 ] foolstring2, test3 foolnumb2:0 @ 1585218328.066928
[ Thread-2_1 ] foolstring1, test3 foolnumb1:1 @ 1585218328.066928
[ Thread-4_2 ] foolstring3, test3 foolnumb3:0 @ 1585218329.0687575
[ Thread-1_1 ] foolstring1, test3 foolnumb1:2 @ 1585218329.0688848

example5:加装封装,将某些操作进行原子化

 1 import time
2 import vthread
3 # 有时候你需要把某些操作进行原子化
4 # 可以把你要原子化的操作写成函数,用vthread.atom装饰就行
5 #==========#
6 # 加锁封装 #
7 #==========#
8 @vthread.thread(2)
9 def foolfunc_():
10
11 @vthread.atom # 将函数加锁封装
12 def do_some_fool_thing1():
13 # pass # do_something
14 print("do some fool thing1 @",time.time())
15 @vthread.atom # 将函数加锁封装
16 def do_some_fool_thing2():
17 # pass # do_something
18 print("do some fool thing2 @", time.time())
19
20 # 执行时就会实现原子操作
21 do_some_fool_thing1()
22 do_some_fool_thing2()
23
24 foolfunc_()

执行的结果如下所示:

[   Thread-1  ] do some fool thing1 @ 1585223133.8172073
[ Thread-1 ] do some fool thing2 @ 1585223133.8172073
[ Thread-2 ] do some fool thing1 @ 1585223133.8172073
[ Thread-2 ] do some fool thing2 @ 1585223133.8172073

原子操作是指独立而不可分割的操作,可以理解为一组不可分割操作集。

其他说明:

# 另外:
# 为了便于调试函数在任意第一次装饰过后会对 print 打猴子补丁
# 自带的 print 函数变成带锁的函数了,还加了些打印线程名字的操作
# 可以通过 vthread.toggle 函数对这些或其他一些功能进行关闭
# 也可以用 vthread.unpatch_all() 直接将 print 还原成系统默认函数
# 更多详细内容可以 help(vthread) # 额外细节:
# 如果想将自己的某些函数进行原子操作的封装可以考虑用 @vthread.atom 装饰那个函数
# 如果你想用原函数的话,你可以用 vthread.orig_func["foolfunc1"] 获得原函数地址
# vthread.orig_func 就是一个包装【原函数名字】对应【原函数地址】的字典。
# 虽然 vthread.atom 可以实现原子操作
# 这里仍然将 lock 暴露出去,用 vthread.lock 就可以拿到这个唯一的线程锁实体 # 为了不用使用者收尾:
# 当使用者装饰任意数量的线程池的时候,都会默认只开一个不计入数量的线程MainMonitor
# 就是监视主线程执行情况,一旦主线程执行完就向线程队列注入相应数量的停止标记
# 因为该线程池的原理就是让主线程变成派发函数的进程,执行到尾部自然就代表
# 分配的任务已经分配完了,这时就可以注入停止标记让线程执行完就赶紧结束掉
# 因为是队列操作不会影响线程效率,只是为了防止在命令行下控制权不交还的情况。
# 当然在之前设计的时候是可以用人为在所有代码最后执行一次 vthread.pool_close_all() 即可解决。
# 但是为了更易用,为了不让使用者在代码最后添加这一句话,就设计了这个监控线程

多线程--vthread的更多相关文章

  1. Python多线程多进程那些事儿看这篇就够了~~

    自己以前也写过多线程,发现都是零零碎碎,这篇写写详细点,填一下GIL和Python多线程多进程的坑~ 总结下GIL的坑和python多线程多进程分别应用场景(IO密集.计算密集)以及具体实现的代码模块 ...

  2. Python中的多进程与多线程(一)

    一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...

  3. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  4. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  5. Java多线程

    一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是一个线程.   进程:进程 ...

  6. .NET基础拾遗(5)多线程开发基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  7. Java多线程基础——对象及变量并发访问

    在开发多线程程序时,如果每个多线程处理的事情都不一样,每个线程都互不相关,这样开发的过程就非常轻松.但是很多时候,多线程程序是需要同时访问同一个对象,或者变量的.这样,一个对象同时被多个线程访问,会出 ...

  8. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  9. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

随机推荐

  1. 关于软链接ln -s 的使用

    1.效果跟windows创建快捷方式是一样的,先找到要被创建的原始文件或目录.然后才能创建. 2.格式:ln  -s   [源文件或目录]   [目标文件或目录] 3.源文件或目录必须是绝对目录. 4 ...

  2. Java Web实现登录验证码(Servlet+jsp)

    1.生成验证码图片(Servlet) import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import j ...

  3. Django学习day13随堂笔记

    每日测验 """ 今日考题 1.什么是django中间件,它的作用是什么,如何自定义中间件,里面有哪些用户可以自定义的方法,这些方法有何特点 2.基于django中间件的 ...

  4. Docker系列(3)- 配置阿里云镜像加速

    step-1 登录阿里云找到容器服务 step-2 找到镜像加速地址 step-3 配置使用 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon ...

  5. java中的swing设计界面时怎么加上背景图片。而不覆盖其他控件?

    通过以下方式设置下背景就可以了: import java.awt.Container; import javax.swing.ImageIcon; import javax.swing.JFrame; ...

  6. PolarDB PostgreSQL logindex 设计

    背景介绍 PolarDB采用了共享存储一写多读架构,读写节点RW和多个只读节点RO共享同一份存储,读写节点可以读写共享存储中的数据:只读节点仅能各自通过回放日志,从共享存储中读取数据,而不能写入,只读 ...

  7. P3645-[APIO2015]雅加达的摩天楼【bfs,根号分治】

    正题 题目链接:https://www.luogu.com.cn/problem/P3645 题目大意 \(n\)个点,\(m\)条狗,第\(i\)条狗可以往左或者右跳恰好\(p_i\)步,开始是\( ...

  8. python接口自动化--json解析神器jsonpath

    前言 做接口测试的时候,大部分情况下返回的是json数据,我们需要对返回的json断言. 当返回的数据量比较大,并且嵌套的层级很深的时候,很多小伙伴不会取值,往往在返回结果取值上浪费很多时间.一直在寻 ...

  9. Winform 控件命名规范

    前言 最近 Winform 项目做得比较多,控件命名规范上常用的能记住,但是有些总要查,写个记录吧.方便以后自己用,大家也可以参考. 标准控件 序号 控件类型简写 控件类型 1 btn Button ...

  10. 从Gartner与IDC三大行业报告,看国产RPA的市场规模与未来发展

    从Gartner与IDC三大行业报告,看国产RPA的市场规模与未来发展 Gartner与IDC的三份报告,描绘出中国RPA的市场规模与未来宏图 文/王吉伟 近期的国产RPA,可谓捷报频频.三个重量级行 ...