简介
- 线程是操作系统能搞够进行运算调度的最小单位。它把被包含在进程之中,所有的线程运行在同一个进程中,共享相同的运行环境,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务
- 一个程序执行的实例就是一个进程
- 同一个进程里的所有线程是共享同一块内存空间的,所以同一个进程的多有线程之间可以直接交流;而进程的内存是独立的,所以两个进程想通信,必须通过一个中间代理来实现
- 创建新线程很简单,创建新进程需要对其父进程进行一次克隆
- 一个线程可以控制和操作同一个进程里的其他线程,但是进程只能操作子进程
join() 程序挂起,知道该线程结束才执行下一步
import threading
import time
def run(n):
print("test", n)
time.sleep(2)
print("task done", n)
start_time = time.time() #线程开始的时间
t_obj = [] #存储线程实例
for i in range(50): #创建50个线程
t = threading.Thread(target = run, args = ("t-%s" %i, ))
t.start() #线程创建后并启动
t_obj.append(t) #为了不阻塞后面的线程启动,不在这里join,先放到一个列表里
for t in t_obj: #循环线程实例列表,等待所有线程执行完毕
t.join()
print("all threads done :", time.time() - start_time)
setDaemon(True) 设置该线程为守护线程,一定要在调用start()函数前调用
import threading
import time
def run(n):
print("test", n)
time.sleep(2)
print("task done", n, threading.current_thread())
start_time = time.time() #线程开始的时间
t_obj = [] #存储线程实例
for i in range(50): #创建50个线程
t = threading.Thread(target = run, args = ("t-%s" %i, ))
t.setDaemon(True) #把当前线程设置为守护进程,该线程是否执行完毕不重要了,主线程执行完毕,程序直接退出,不再等待子线程执行完毕
t.start() #线程创建后并启动
t_obj.append(t) #为了不阻塞后面的线程启动,不在这里join,先放到一个列表里
print(threading.active_count())
print("all threads done :", time.time() - start_time, threading.current_thread())
lock.acquire() 只有一个线程能成功地获取锁,然后继续执行代码,其他线程就继续等待知道获得锁为止;获得锁的线程用完后一定要释放锁,否则程序成为死线程。锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处是阻止了多线程并发执行,包括锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。
import threading
import time
def run(n):
lock.acquire() #获得锁,只要获得了锁,程序就变成了串行
global num
num += 1
# time.sleep(1) #验证是否为单线程
lock.release() #释放锁
lock = threading.Lock() #创建一个锁
num = 0
t_obj = [] #存储线程实例
for i in range(50): #创建50个线程
t = threading.Thread(target = run, args = ("t-%s" %i, ))
t.start() #线程创建后并启动
t_obj.append(t) #为了不阻塞后面的线程启动,不在这里join,先放到一个列表里
for t in t_obj: #循环线程实例列表,等待所有线程执行完毕
t.join()
print("all threads done")
print("num", num)
RLock()类(递归锁) 可重入锁对象,使单线程可以再次获得已经获得了的锁(递归锁定)
import threading
def run1():
print("-----start run1-----")
lock.acquire() #获取锁
global num #全局变量num
num += 1
lock.release() #释放锁
return num #返回num值
def run2():
print("-----start run2-----")
lock.acquire()
global num2
num2 += 1
lock.release()
return num2
def run3():
lock.acquire()
res = run1()
print("-----between run1 and run2-----")
res2 = run2()
lock.release()
print(res, res2)
num, num2 = 0, 0
lock = threading.RLock() #创建一个递归锁
for i in range(10):
t = threading.Thread(target = run3) #启动run3
t.start()
while threading.active_count() != 1: #启动10个线程加上主线程一共11个线程,如果当前线程等于1,即子线程都结束了,只剩下主线程
print(threading.active_count())
else:
print("------all threads done------")
print(num, num2)
BoundedSemaphore()类 为等待锁的线程提供一个类似“侯等室”的结构,并且后等的个数不允许超过指定初始值
import threading
import time
def run(n):
semaphore.acquire()
time.sleep(1)
print("run the thread: %s\n" % n)
semaphore.release()
semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
for i in range(20):
t = threading.Thread(target = run, args = (i, ))
t.start()
while threading.active_count() != 1:
pass
else:
print("----all threads done----")
Event()类 用于线程间通信, 即程序中的其中一个线程需要通过判断某个线程的状态来确定自己下一步的操作
1、event.set() 设置信号
使用event.set()方法时,可以设置对象内部的信号标志为真。可以使用event.isSet()方法判断其内部信号标志为的状态,当使用set()方法后,isSet()方法返回真True
2、event.clear() 清除信号
使用event.clear() 可以清除对象内部的信号标志,即将其设为默认值--假False,当使用clear()方法后,isSet() 方法返回假False
3、event.wait(timeout) 等待
只有在内部信号为真时,才会执行并返回,当内部信号位假时,则会一直处于阻塞线程至等待其他线程调用set()方法
4、isSet() 获取内部标志位,返回True或者False
import threading, time
event = threading.Event()
def lighter():
count = 0
event.set() #先设为绿灯 # 默认为False,调用一次set表示True
while True:
if count > 5 and count < 10:
event.clear() #把标志位清空
print("---红灯了---")
elif count > 10:
event.set() #变绿灯
count = 0
else:
print("-----绿灯了-----")
time.sleep(1)
count += 1
def car(name):
while True:
if event.isSet():
print("[%s] 开动---" % name )
time.sleep(1)
else:
print("[%s] 看见红灯了,等待---" % name)
event.wait() #括号内可以带数字执行,数字表示等待的秒数,不带数字表示一直阻塞状态
print("[%s] 看见绿灯了,开动----" % name)
light = threading.Thread(target = lighter,)
light.start()
car1 = threading.Thread(target = car, args = ("Tesla", ))
car1.start()
queue队列模块
class queue.Queue(maxsize = 0) 先进先出,queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是一个整数,指明队列中能存放的上限,一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉,如果maxsize小于或者等于0,队列大小没有限制。
import queue
q = queue.Queue()
for i in range(5):
q.put(i) #添加数据
while not q.empty(): #empty()函数:如果队列为空返回True,否则返回False
print(q.get()) #获取队列
#----------------------------------------------------------------------
0
1
2
3
4
class queue.LifoQueue(maxsize = 0) 后进先出,与栈类似
import queue
q = queue.LifoQueue()
for i in range(5):
q.put(i) #添加数据
while not q.empty(): #empty()函数:如果队列为空返回True,否则返回False
print(q.get()) #获取队列
#--------------------------------------------
4
3
2
1
0
class queue.PrioritQueue(maxsize = 0) 优先级队列
import queue
q = queue.PriorityQueue()
q.put((3, "第三"))
q.put((1, "第一"))
q.put((-1, "负一"))
q.put((10, "第十"))
while not q.empty():
print(q.get())
#----------------------------------------------------
(-1, '负一')
(1, '第一')
(3, '第三')
(10, '第十')
生产者-消费者问题
import threading, time
import queue
q = queue.Queue(maxsize = 10) #最多添加十个
def Producer(name): #生产者
while True:
count = 1
while True:
q.put("包子%s" % count)
print("生产了包子", count)
count += 1
time.sleep(0.1)
def Consumer(name): #消费者
while True:
print("[%s] 取到[%s] 并且吃了它。。。" % (name, q.get()))
time.sleep(1)
p = threading.Thread(target = Producer, args = ("DaWang",))
c = threading.Thread(target = Consumer, args = ("XiaoWang",))
c1 = threading.Thread(target = Consumer, args = ("XiaoLi",))
p.start()
c.start()
c1.start()