线程


JoinableQueue的使用

from multiprocessing import JoinableQueue, Queue

q = JoinableQueue()
q.put(1)
q.put(2)

print(q.get())
q.task_done() # 告诉容器已经处理完了一个数据
q.task_done() # 有几次就要调用几次
q.join() # 也是一个阻塞函数 一直到队列中的数据被处理完毕(task_done的调用次数等于队列中数据数量)
print('处理完毕')
print(q.get())
print(q.empty())
JoinableQueue

生产者消费者模型

'''
小明作为消费者 要吃热狗
生产者 负责做热狗
问题:
小明不清楚对方会生产多少热狗
'''

from multiprocessing import Process, Queue, JoinableQueue
import time, random


# 生产者
def make_hot_dog(q):
for i in range(1, 6):
time.sleep(random.randint(1, 3))
print('生产者 生产了hot_dog%s' % i)
q.put('hot_dog%s' % i)


# 消费者
def eat_hot_dog(q):
while True:
time.sleep(random.randint(1, 2))
hot_dog = q.get()
print('小明吃了%s' % hot_dog)
q.task_done()


if __name__ == '__main__':
# 共享数据的队列
q = JoinableQueue()
# 生产者
p1 = Process(target=make_hot_dog, args=(q,))
p2 = Process(target=make_hot_dog, args=(q,))
p1.start()
p2.start()
# 消费者
c1 = Process(target=eat_hot_dog, args=(q,))
c1.daemon = True
c1.start()
# 先要确定生产者已经不会再生产了
p1.join()
p2.join()
print('生产已经结束了???')
# 再确定队列中的数据都被处理完成
q.join()
print('小明已经全部吃完了。。。')
c1.terminate()
# 小明就不需要在吃了
生产者消费者模型

线程
线程指的是一条流水线,整个执行过程中的总称,也是一个抽象概念
线程是CPU的最小执行单位,是具体负责执行代码的

进程是一个资源但闻,其中包括了该程序运行所需的所有子资源

线程的特点:
一个进程中至少包含一个线程,是由操作系统自动创建的,称之为主线程
一个进程中可以有任意数量的线程
创建线程的开销对比而言 要小的多
同一个进程中的线程间数据是共享的(最主要的特点)
如何使用:使用的方式与进程一致
不同的是:创建线程的代码 可以写在任何位置

from threading import Thread

第一种 开启线程的方式 直接实例化Thread类
def task():
print('running .....')


t = Thread(target=task)
t.start()
线程使用1
2.继承Thread类 覆盖run方法
class My(Thread):
def run(self):
print('running....')


t = My()
t.start()
线程使用2

开启线程速度比开启进程快很多
主线程任务执行完毕后 进程不会立即结束 会等待所有子线程全部执行完毕
在同一个进程 所有线程都是平等的 没有子父这么一说

from threading import Thread

import time


def task():
print('子线程 running 。。。')
time.sleep(3)
print('子线程over。。。')


t = Thread(target=task)
t.start()
print('main over')
线程效果

线程与进程的区别
一:数据是共享的
二:创建进程 与创建线程的开销 线程比进程快大约是一百多倍
线程安全也是通过锁来保证,锁的用法与进程中的锁一模一样

import time

from threading import Thread, Lock

num = 10
lock = Lock()


def task():
global num
lock.acquire()
a = num
time.sleep(0.1)
num = a - 1
lock.release()


ts = []
for i in range(10):
t = Thread(target=task)
t.start()
ts.append(t)

for t in ts:
t.join()

print(num)
线程的锁

死锁:
当你今后在开发一些高并发程序时 很有可能出现线程/进程安全问题
解决方案只能加锁但是在使用锁时,很有可能出现死锁问题
同一把锁调用了多次acquire 导致死锁问题(最low的死锁问题)
有多把锁一个线程抢到一把锁,要完成任务必须同时抢到所有锁,这将导致死锁问题

如何避免:
1.能不加锁就不加锁
2.如果一定要加 要保证锁只有一把

线程对象的常用属性

from threading import Thread

# Thread对象常用属性
t = Thread(name='一个线程')
print(t.name)
print(t.is_alive()) # 线程名称
print(t.daemon)
print(t.ident)

# threading 模块中的常用属性
import threading
import os

t = threading.current_thread() # 获取当前线程对象
print(t)
print(os.getpid())


def task():
print(threading.current_thread())


print(threading.active_count()) # 获取目前活跃的线程数量
Thread(target=task).start()
print(threading.active_count()) # 正在运行中的线程数量
ts = threading.enumerate() # 返回所有正在运行的线程对象
print(ts)
线程对象的常用属性

信号量 可以控制同一时间 有多少线程可以并发的访问
不是用来处理线程安全问题

守护线程
守护线程会在主线程结束后立即结束 即使任务没有完成
主线程 会等待所有子线程全部完成后结束

守护线程会在所有非守护线程结束后 结束
主线 守护进程
主线程要等待所有子线结束

from threading import Thread, current_thread
import time


def task1():
print('%s正在运行。。。' % current_thread().name)
time.sleep(3)
print('%s over 。。。' % current_thread().name)


def task2():
print('%s正在运行。。。' % current_thread().name)
time.sleep(10)
print('%s over 。。。' % current_thread().name)


t1 = Thread(target=task1)
t2 = Thread(target=task2)
t1.start()
t2.start()
print('over')
主线程等待所有子线程
原文地址:https://www.cnblogs.com/ShenJunHui6/p/10490122.html