多进程(补充),多线程,锁

Posted gengbinjia

tags:

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

多进程补充
joinable Queue

q=JoinableQueue
q.put(1)
q.put(2)
print(q.get())
q.task_done() 告诉容器已经处理完成了一个数据 有几个数据就要调用几次
q.task_done()

q.join() 也是一个阻塞函数 一直到队列中的数据被处理完毕(task_done的调用次数等于队列中的数据数量)
print(‘处理完成‘)

技术图片
# 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("33[46m生产者 生产了hot_dog%s33[0m" % 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()
#
#     # print("完成了吗???")
#     #先要确定生产者已经不会再生产了
#     p1.join()
#     p2.join()
#
#     print("生产已经结束了...")
#     #再确定队列中的所有数据都被处理完成
#     q.join()
#     print("思聪已经全部吃完了....")
#
#
#     # c1.terminate()
#     #王思聪就不需要在吃了
生产者消费者模型

 




进程池
1.多线程理论(重点)
2.多线程使用方法(重点)
两种创建方式
常用属性

互斥锁
死锁


操作系统就像一个工厂

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

进程是一个资源单位,其中包括了改程序运行所需的所有资源
线程相当于车间里的一条流水线
线程的特点:
一个进程中至少包括一个线程 是由操作系统自动创建的 称之为主线程
一个进程中可以有任意数量的线程
创建线程的开销对比进程而言 要小的多
同一个进程中的线程间数据是共享的(最主要的特点)

如何使用:使用的方式与进程一致
不同的是:创建线程的代码可以写在任何位置

from threading import Thread
技术图片
# 第一种 开启线程的方式 直接实例化Thread类
# from threading import Thread
#
# def task():
#     print(‘running....‘)
#
#
# if __name__ == ‘__main__‘:
#     t=Thread(target=task)
#     t.start()
#     print(‘over‘)
#
# # 2.继承Thread类  覆盖run方法
# class MyThread(Thread):
#     def run(self):
#         print(‘running...‘)
# MyThread().start()
# #t=MyThread()
# #t.start()
两种线程创建方式

 




开启线程速度 比开启进程快很多

主线程任务执行完毕后 进程不会立即结束 会等待所有子线程执行完毕
在同一进程中 所有线程都是平等的 没有子父一说
from threading import Thread
import time

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

t = Thread(target=task)
t.start()
print("main over")

线程与进程的区别之一 数据是共享的
区别二 创建进程与创建线程的开销 大约是一百多倍

from multiprocessing import  Process
import os
def task():
    print(os.getpid())
    pass

if __name__ == __main__:

    start = time.time()
    ps = []
    for i in range(100):
        p = Thread(target=task)
        # p = Process(target=task)
        p.start()
        ps.append(p)

    for p in ps:
        p.join()

    print(time.time()-start)

 



线程安全也是通过锁来保证 所得用法与进程中一模一样
技术图片
# 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)
线程安全

 



开发高并发程序很有可能遇到安全问题
解决方案只有加锁 但是在使用锁时 很有可能出现死锁问题

出现死锁问题的两种情况:
1.对同一把锁调用了多次acquire 导致死锁问题(最low的死锁问题 应该避免这种问题)
2.有多把锁,一个线程抢一把锁,要完成任务必须同时抢到所有的锁 将导致死锁问题
技术图片
from threading import Lock,Thread
import time

# lock = Lock()
# lock.acquire()
# lock.acquire()
# print("over")

# 一个盘子 和一双筷子
# lock1 = Lock()
# lock2 = Lock()
#
# def task1(name):
#     lock1.acquire()
#     print("%s 抢到了盘子" % name)
#
#     time.sleep(1)
#
#     lock2.acquire()
#     print("%s 抢到了筷子" % name)
#
#     print("%s 吃饭了....." % name)
#
#     lock1.release()
#     lock2.release()
#
#
# def task2(name):
#     lock2.acquire()
#     print("%s 抢到了筷子" % name)
#
#     lock1.acquire()
#     print("%s 抢到了盘子" % name)
#
#     print("%s 吃饭了....." % name)
#
#     lock1.release()
#     lock2.release()
#
#
#
# t1 = Thread(target=task1,args=("渣渣辉",))
# t1.start()
#
# t2 = Thread(target=task2,args=("大导演",))
# t2.start()
死锁

 


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

RLock只能防止同一个问题 统一线程多次执行acquire

from threading import RLock

# lock = RLock()
# lock.acquire()
# lock.acquire()
# lock.acquire()
# lock.acquire()
#
# print("over")
# lock = RLock()
#
# def task1():
#     lock.acquire()
# def task2():
#     lock.acquire()
#
# Thread(target=task1).start()
# Thread(target=task2).start()

 




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

from threading import Semaphore

s_lock = Semaphore(3)

def task():
    s_lock.acquire()
    time.sleep(1)
    print("run.....")
    s_lock.release()

for i in range(20):
    t = Thread(target=task)
    t.start()

 



threading.current_thread() # 获取当前线程
threading.active_count() 正在运行中的线程数量
threading.enumerate() 返回所有正在运行的线程对象


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


守护线程会在所有非守护线程结束后 结束*****

主线 守护线程
主线程要等待所有子线程结束

from threading import Semaphore

s_lock = Semaphore(3)

def task():
    s_lock.acquire()
    time.sleep(1)
    print("run.....")
    s_lock.release()

for i in range(20):
    t = Thread(target=task)
    t.start()

 

以上是关于多进程(补充),多线程,锁的主要内容,如果未能解决你的问题,请参考以下文章

整数的无锁多线程

synchronized锁多线程同步的原理是咋样的?

无锁多线程编程初步(基础部分)

单进程单线程的Redis如何能够高并发

对Redis 单进程单线程模型的理解(网摘)

《C++多线程编程》学习笔记