Lazy loaded image
python
Words 3257Read Time 9 min
2024-10-28

多线程(Thread)并行计算

开始学习python

Python 使用多线程的方法主要有两种,第一种函数,第二种用类包装的线程对象
  1. 函数式
语法:thread.start_new_thread ( function, args[, kwargs] )
thread.start_new_thread( print_time, ("Thread-1", 2, )
参数说明:
  • function - 线程函数。
  • args - 传递给线程函数的参数,他必须是个tuple类型。
  • kwargs - 可选参数。
2. 线程模块
Python通过两个标准库_threadthreading提供对线程的支持。_thread提供了低级别的、原始的线程以及一个简单的锁。threading 这个模块在较低级的模块 _thread 基础上建立较高级的线程接口。
虽然他们没有在下面列出,这个模块仍然支持Python 2.x系列的这个模块下以 camelCase (驼峰法)命名的方法和函数。
  • threading.current_thread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.active_count(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
线程对象
class threading.Thread(group=Nonetarget=Nonename=Noneargs=()kwargs={}daemon=None)
调用这个构造函数时,必需带有关键字参数。参数如下:
  1. group 应该为 None;为了日后扩展 ThreadGroup 类实现而保留。
  1. target 是用于 run() 方法调用的可调用对象。默认是 None,表示不需要调用任何方法。name 是线程名称。默认情况下,由 "Thread-N" 格式构成一个唯一的名称,其中 N 是小的十进制数。
  1. args 是用于调用目标函数的参数元组。默认是 ()
  1. kwargs 是用于调用目标函数的关键字参数字典。默认是 {}
  1. 如果不是 Nonedaemon 参数将显式地设置该线程是否为守护模式。 如果是 None (默认值),线程将继承当前线程的守护模式属性。如果子类型重载了构造函数,它一定要确保在做任何事前,先发起调用基类构造器(Thread.__init__())。
 
  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • is_alive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。
锁对象
class threading.Lock
实现原始锁对象的类。一旦一个线程获得一个锁,会阻塞随后尝试获得锁的线程,直到它被释放;任何线程都可以释放它。需要注意的是 Lock 其实是一个工厂函数,返回平台支持的具体锁类中最有效的版本的实例。
acquire(blocking=Truetimeout=-1)可以阻塞或非阻塞地获得锁。当调用时参数 blocking 设置为 True (缺省值),阻塞直到锁被释放,然后将锁锁定并返回 True 。在参数 blocking 被设置为 False 的情况下调用,将不会发生阻塞。如果调用时 blocking 设为 True 会阻塞,并立即返回 False ;否则,将锁锁定并返回 True。当浮点型 timeout 参数被设置为正值调用时,只要无法获得锁,将最多阻塞 timeout 设定的秒数。timeout 参数被设置为 1 时将无限等待。当 blocking 为 false 时,timeout 指定的值将被忽略。如果成功获得锁,则返回 True,否则返回 False (例如发生 超时 的时候)。在 3.2 版更改: 新的 timeout 形参。在 3.2 版更改: 现在如果底层线程实现支持,则可以通过POSIX上的信号中断锁的获取。
release()释放一个锁。这个方法可以在任何线程中调用,不单指获得锁的线程。当锁被锁定,将它重置为未锁定,并返回。如果其他线程正在等待这个锁解锁而被阻塞,只允许其中一个允许。在未锁定的锁调用时,会引发 RuntimeError 异常。没有返回值。locked()如果获得了锁则返回真值。
递归锁对象
重入锁是一个可以被同一个线程多次获取的同步基元组件。在内部,它在基元锁的锁定/非锁定状态上附加了 "所属线程" 和 "递归等级" 的概念。在锁定状态下,某些线程拥有锁 ; 在非锁定状态下, 没有线程拥有它。
若要锁定锁,线程调用其 acquire() 方法;一旦线程拥有了锁,方法将返回。若要解锁,线程调用 release() 方法。 acquire()/release() 对可以嵌套;只有最终 release() (最外面一对的 release() ) 将锁解开,才能让其他线程继续处理 acquire() 阻塞。
递归锁也支持 上下文管理协议
class threading.RLock此类实现了重入锁对象。重入锁必须由获取它的线程释放。一旦线程获得了重入锁,同一个线程再次获取它将不阻塞;线程必须在每次获取它时释放一次。
条件对象
信号量对象
事件对象
定时器对象
栅栏对象

锁和线程同步

情形:
一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。
那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。
 
为了避免这种情况,引入了锁的概念。
每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。
经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。
例子1:
例子2:

线程优先级队列( Queue)

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

多进程并行处理

 
 
  1. 菜鸟教程 - Python 多线程
     
     
     
    上一篇
    宏的用法
    下一篇
    Guide to Linux System

    Comments
    Loading...