多线程--vthread

Posted zhiminyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程--vthread相关的知识,希望对你有一定的参考价值。

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

 

以上是关于多线程--vthread的主要内容,如果未能解决你的问题,请参考以下文章

多线程 Thread 线程同步 synchronized

多个用户访问同一段代码

线程学习知识点总结

多个请求是多线程吗

VMware Workstation 10.0 不可恢复错误: (vthread-13)

python小白学习记录 多线程爬取ts片段