多线程(threading module)

一、线程与进程

线程定义:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

进程定义:An executing instance of a program is called a process.(程序的执行实例称为进程。)

线程与进程的区别:

  1. 线程共享创建它的进程的地址空间; 进程有自己的地址空间。
  2. 线程可以直接访问其进程的数据段; 进程拥有自己父进程数据段的副本。
  3. 线程可以直接与其进程的其他线程通信; 进程必须使用进程间通信来与兄弟进程通信。
  4. 新线程很容易创建; 新流程需要复制父流程。
  5. 线程可以对同一进程的线程进行相当大的控制; 进程只能控制子进程。
  6. 对主线程的更改(取消,优先级更改等)可能会影响进程的其他线程的行为; 对父进程的更改不会影响子进程。

二、Python GIL(Global Interpreter Lock)

  --> 全局解释器锁 :在同一时刻,只能有一个线程进入解释器。

三、threading 模块

3.1 线程的2种调用方式

直接调用

 1 import threading
 2 import time
 3
 4 def sayhi(num): #定义每个线程要运行的函数
 5
 6     print("running on number:%s" %num)
 7
 8     time.sleep(3)
 9
10 if __name__ == ‘__main__‘:
11
12     t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
13     t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
14
15     t1.start() #启动线程
16     t2.start() #启动另一个线程
17
18     print(t1.getName()) #获取线程名
19     print(t2.getName())

继承式调用

 1 import threading
 2 import time
 3
 4
 5 class MyThread(threading.Thread):
 6     def __init__(self,num):
 7         threading.Thread.__init__(self)
 8         self.num = num
 9
10     def run(self):#定义每个线程要运行的函数
11
12         print("running on number:%s" %self.num)
13
14         time.sleep(3)
15
16 if __name__ == ‘__main__‘:
17
18     t1 = MyThread(1)
19     t2 = MyThread(2)
20     t1.start()
21     t2.start()

3.2 常用方法(Join/Daemon)

  join() --> 在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

  setDaemon(True) -->  将线程声明为守护线程,必须在start() 方法调用之前设置,守护线程随主线程结束而结束。

其他方法:

 1 threading 模块提供的其他方法:
 2 # threading.currentThread(): 返回当前的线程变量。
 3 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
 4 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
 5 # 除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
 6 # run(): 用以表示线程活动的方法。
 7 # start():启动线程活动。
 8 # join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
 9 # isAlive(): 返回线程是否活动的。
10 # getName(): 返回线程名。
11 # setName(): 设置线程名。

Method

3.3 同步锁(Lock)

  r = threading.Lock()  r.acquire() --> 加锁  r.release() --> 解锁

 1 import time
 2 import threading
 3
 4 def addNum():
 5     global num #在每个线程中都获取这个全局变量
 6     # num-=1
 7     lock.acquire()
 8     temp=num
 9     print(‘--get num:‘,num )
10     #time.sleep(0.1)
11     num =temp-1 #对此公共变量进行-1操作
12     lock.release()
13
14 num = 100  #设定一个共享变量
15 thread_list = []
16 lock=threading.Lock()
17
18 for i in range(100):
19     t = threading.Thread(target=addNum)
20     t.start()
21     thread_list.append(t)
22
23 for t in thread_list: #等待所有线程执行完毕
24     t.join()
25
26 print(‘final num:‘, num )

3.4 线程死锁和递归锁

  在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。下面是一个死锁的例子:

 1 import threading,time
 2
 3 class myThread(threading.Thread):
 4     def doA(self):
 5         lockA.acquire()
 6         print(self.name,"gotlockA",time.ctime())
 7         time.sleep(3)
 8         lockB.acquire()
 9         print(self.name,"gotlockB",time.ctime())
10         lockB.release()
11         lockA.release()
12
13     def doB(self):
14         lockB.acquire()
15         print(self.name,"gotlockB",time.ctime())
16         time.sleep(2)
17         lockA.acquire()
18         print(self.name,"gotlockA",time.ctime())
19         lockA.release()
20         lockB.release()
21     def run(self):
22         self.doA()
23         self.doB()
24 if __name__=="__main__":
25
26     lockA=threading.Lock()
27     lockB=threading.Lock()
28     threads=[]
29     for i in range(5):
30         threads.append(myThread())
31     for t in threads:
32         t.start()
33     for t in threads:
34         t.join()

deadLock

解决办法:使用递归锁

  即重新定义一把锁:lock = threading.RLock() --> 递归锁

  将所有的锁替换为递归锁即可。递归锁可以重复加锁。

  RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

3.5 信号量(Semaphore)--> 相当于一把锁

  信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。

  计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)

  BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。

 1 import threading,time
 2 class myThread(threading.Thread):
 3     def run(self):
 4         if semaphore.acquire():
 5             print(self.name)
 6             time.sleep(5)
 7             semaphore.release()
 8 if __name__=="__main__":
 9     semaphore=threading.Semaphore(5)
10     thrs=[]
11     for i in range(100):
12         thrs.append(myThread())
13     for t in thrs:
14         t.start()

Semaphore

3.6 条件变量同步(Condition)--> 锁

  有一类线程需要满足条件之后才能够继续执行,Python提供了threading.Condition 对象用于条件变量线程的支持,它除了能提供RLock()或Lock()的方法外,还提供了 wait()、notify()、notifyAll()方法。

lock_con=threading.Condition([Lock/Rlock]): 锁是可选选项,不传入锁,对象自动创建一个RLock()。

1 wait():条件不满足时调用,线程会释放锁并进入等待阻塞;
2 notify():条件创造后调用,通知等待池激活一个线程;
3 notifyAll():条件创造后调用,通知等待池激活所有线程。

 1 import threading,time
 2 from random import randint
 3 class Producer(threading.Thread):
 4     def run(self):
 5         global L
 6         while True:
 7             val=randint(0,100)
 8             print(‘生产者‘,self.name,":Append"+str(val),L)
 9             if lock_con.acquire():
10                 L.append(val)
11                 lock_con.notify()
12                 lock_con.release()
13             time.sleep(3)
14 class Consumer(threading.Thread):
15     def run(self):
16         global L
17         while True:
18                 lock_con.acquire()
19                 if len(L)==0:
20                     lock_con.wait()
21                 print(‘消费者‘,self.name,":Delete"+str(L[0]),L)
22                 del L[0]
23                 lock_con.release()
24                 time.sleep(0.25)
25
26 if __name__=="__main__":
27
28     L=[]
29     lock_con=threading.Condition()
30     threads=[]
31     for i in range(5):
32         threads.append(Producer())
33     threads.append(Consumer())
34     for t in threads:
35         t.start()
36     for t in threads:
37         t.join()

Condition Demo

3.7 同步条件(Event)

条件同步和条件变量同步差不多意思,只是少了锁功能,因为条件同步设计于不访问共享资源的条件环境。event=threading.Event():条件环境对象,初始值 为False;

1 event.isSet():返回event的状态值;
2
3 event.wait():如果 event.isSet()==False将阻塞线程;
4
5 event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
6
7 event.clear():恢复event的状态值为False。

示例:

 1 import threading,time
 2 class Boss(threading.Thread):
 3     def run(self):
 4         print("BOSS:今晚大家都要加班到22:00。")
 5         event.isSet() or event.set()
 6         time.sleep(5)
 7         print("BOSS:<22:00>可以下班了。")
 8         event.isSet() or event.set()
 9 class Worker(threading.Thread):
10     def run(self):
11         event.wait()
12         print("Worker:哎……命苦啊!")
13         time.sleep(0.25)
14         event.clear()
15         event.wait()
16         print("Worker:OhYeah!")
17 if __name__=="__main__":
18     event=threading.Event()
19     threads=[]
20     for i in range(5):
21         threads.append(Worker())
22     threads.append(Boss())
23     for t in threads:
24         t.start()
25     for t in threads:
26         t.join()

3.8 队列(queue)-->多线程利器

queue中的方法:

创建一个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。

将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。

将一个值从队列中取出
q.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。

Python Queue模块有三种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。  class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。             class queue.LifoQueue(maxsize)
3、还有一种是优先级队列级别越低越先出来。   class queue.PriorityQueue(maxsize)

此包中的常用方法(q = Queue.Queue()):
q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作

示例:

 1 import threading,queue
 2 from time import sleep
 3 from random import randint
 4 class Production(threading.Thread):
 5     def run(self):
 6         while True:
 7             r=randint(0,100)
 8             q.put(r)
 9             print("生产出来%s号包子"%r)
10             sleep(1)
11 class Proces(threading.Thread):
12     def run(self):
13         while True:
14             re=q.get()
15             print("吃掉%s号包子"%re)
16 if __name__=="__main__":
17     q=queue.Queue(10)
18     threads=[Production(),Production(),Production(),Proces()]
19     for t in threads:
20         t.start()

Demo

原文地址:https://www.cnblogs.com/horror/p/9343764.html

时间: 2024-10-12 04:06:55

多线程(threading module)的相关文章

Python 多线程threading模块

首先,我们在了解多线程时需要理解的就是什么是多线程,按照官方的解释就是:多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术. 在我自学到这里的时候,通过会在想进程和线程到底是有什么区别,我的理解就是: 进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,一个进程可以包含多个线程. 下面就以简单的例子来加强我们对python 线程的理解. 默认情况下,我们在没有启动线程的时候,可以看一下程序总的运行时间,应该是每个函数

多进程(mutiprocessing)与多线程(Threading)之多线程

多线程(threading) 多线程与多进程其实大同小异,他们有很多方法从名字到功能都是一样,比如都有start(),join(),都有守护线程/进程deamon. 一个简单的栗子: import threading import os,time def loop(): for i in range(5): t = threading.Thread(name=str(i)) t.start() print('thread %s is running!'%t.name) print('thread

多进程 multiprocessing 多线程Threading 线程池和进程池concurrent.futures

multiprocessing.procsess 定义一个函数 def func():pass 在if __name__=="__main__":中实例化 p = process(target=子进程要执行的函数,args(函数的参数且必须以元组的方式传参)) p.start() 开启子进程 p.join() 感知子进程的结束,主进程等待子进程执行完后才退出 p.terminate() 结束一个子进程 p.is_alive() 查看某个进程是否还在运行 属性 p.name p.pid

再看python多线程------threading模块

现在把关于多线程的能想到的需要注意的点记录一下: 关于threading模块: 1.关于 传参问题 如果调用的子线程函数需要传参,要在参数后面加一个","否则会抛参数异常的错误. 如下: 1 for i in xrange(5): 2 threads.append(threading.Thread(target=worker,args=(i,))) 2.关于join()阻塞 join()方法一旦被调用,这个线程就会被阻塞住,等其他线程执行完才执行自身.当我们在主线程A中,创建了n个子线

python多线程-threading模块

threading 是我们常用的用于 python 多线程的模块,其功能更加丰富.下面我们就来开始学习这个模块. 同样的,我这里声明一样我使用的版本是 python2.7,不同版本直接可能存在差异. 老规矩,使用 help() 函数获取帮助文档,看看里面有什么内容. threading 模块中提供了一个 thread 的类,注意不要和 thread 模块搞混了,两者差别还是很大的.thread 这个类可以实例化一个对象,每个对象代表一个线程,可以调用其中的 run() 方法来开启一个线程的运行.

多线程-Threading

线程基础 参看[python线程指南] http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html 线程5种状态 - 新建- 就绪- 运行- 阻塞- 死亡 阻塞的三种情况: 同步阻塞:是指处于竞争锁定的状态,线程请求锁定时将进入这个状态,一旦成功获得锁定又恢复到运行状态:等待阻塞:是指等待其他线程通知的状态,线程获得条件锁定后,调用"等待"将进入这个状态,一旦其他线程发出通知,线程将进入同步阻塞状态,再次竞争条件锁定: 其他阻

Python多线程threading用法

Python里面经常会用到多线程,即所有的方法在同一时间开始运行,而不是按顺序一个一 个运行.所用到的模块为threading,下面详解threading用法. 我们写三个方法,one.two.three并正常运行. 这里只截图了one()方法,two.three与one内容一样. 按下面图中的运行方式,三个函数是分别在不同时间运行的. 我们用threading使三个方法在同一时间运行   定义一个线程池并把要运行的线程都写到这个线程池列表里: threads= [] #定义一个线程池t1 =

[Python 多线程] threading.local类 (六)

在使用threading.local()之前,先了解一下局部变量和全局变量. 局部变量: import threading import time def worker(): x = 0 for i in range(100): time.sleep(0.0001) x += 1 print(threading.current_thread(),x) for i in range(10): threading.Thread(target=worker).start() 运行结果: <Thread

python进程相关 - 多线程threading库

概念 多线程类似于同时执行多个不同程序, 优点 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度 程序的运行速度可能加快 在一些等待的任务实现上如用户输入.文件读写和网络收发数据等,线程就比较有用了.在这种情况下我们可以释放一些珍贵的资源如内存占用等等. 基础知识 线程在执行过程中与进程还是有区别的.每个独立的线程有一个程序运行的入口.顺序执行序列和程序的出口.但是线程不能够独立执行