Fork me on GitHub

多进程初探


搞定多进程与多线程

多线程

概念

程序
: 代码以文本的形式存入一个文档

进程
: 程序运行的一个状态,包含地址空间、内存、数据栈等
每个进程由自己==完全独立==的运行环境,多进程共享数据

轻量化的进程

  • 一个进程的多个线程间共享数据和上下文运行环境
  • 共享、互斥问题

线程
: 一个进程的独立运行片段,一个进程可以由多个线程

全局解释器锁(GIL)

  • Python代码的执行是由python虚拟机进行控制
  • 在主循环中有一个控制线程在执行

Python包

thread: 有问题,不好用

  • python3: _thread
    *  `import _thread as thread ` 
    

    threading: 通行的包

  • 直接利用threading.Thread生成Thread
  • t = threading.Thread(target=xxx, args=())
  • t.start(): 启动多线程,可独立于主线程
  • t.join() : 等待多线程执行完成

守护线程 daemon

子线程会在主线程结束后自动退出**,一般认为守护线程不重要或不允许离开主线程独立运行

  • 设置守护线程–在t.start()
    * `t.setDaemon(True)`
    
1
2
3
4
if __name__ == "__main__"
main()
while True:
time.sleep(5)

启动线程–使用多线程执行某个函数

thread.start_new_thread(loop,()

理解启动多线程
: 相当于给多个工人分配任务,自己可以做别的事情,等自己事情做完了,工人也恰好完工(完成时间非常快)

注意事项

  1. 启动多线程函数为 ==start_new_thread==
  2. 参数为两个,一个是运行的==函数名==,另一个是==函数参数==作为元组使用,若为空,则使用空元组,若函数只有一个参数,则在参数后需要一个==逗号==,标识为元组
    启动多线程
  3. ==一定要使用while语句==,因为启动多线程后本程序就作为主线程存在,如果主线程执行完毕,则子线程可能也会没执行完就终止

共享变量

共享变量
: 当多个线程同时访问一个相同变量时,会产生共享变量问题,即会产生冲突

解决变量

锁(Lock)


: 是一个标志,表示一个线程在占用一些资源

使用方法
  1. 上锁
  2. 可以放心使用共享资源
  3. 取消锁,释放锁
1
2
3
4
5
6
7
8
import threading

lock = threading.Lock()
# 上锁,申请锁
lock.acquire()

# 使用结束后,释放锁
lock.release()

线程安全问题

概念
: 如果一个资源/变量,对于多线程来说,不用加锁也不会引起任何问题,则称为线程安全

类型

  1. 线程安全变量: queue
  2. 线程不安全变量: list 、 set 、 dict

生产者消费问题

一个模型,可以用来搭建消息队列

queue
: 一个用来存放变量的数据结构,特点为先进先出,内部元素排队,可以理解为一个特殊的list

方法

  • queue.Queue() : 生成队列的实例
  • queue.qsize() : 计算队列的长度
  • queue.push() : 将数据放入队列中
  • queue.get() : 从queue中取出一个值
1
2
3
4
5
# python2
from Queue import Queue

# python3
import queue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import threading
import time

# 直接继承Thread方法
class Producer(threading.Thread)
def run(self):
global queue
count = 0
while True:
# qsize计算队列的长度
if queue.qsize() < 1000
for i in range(100):
count = count + 1
msg = "生产产品" + str(count)
# 将数据放入队列中
queue.put(msg)
print(msg)
time.sleep(0.5)
1
2
3
4
5
6
7
8
9
10
class Consumer(threading.Thread)    
def run(self):
global queue
while True:
if queue.qsize() > 100
for i in range(3):
# get是从queue中取出一个值
msg = self.name + "消费了" + queue.get()
print(msg)
time.sleep(1)

解释
: 对于继承Thread,必须重写run(self)函数,run(self)函数为调用Thread时,自动调用的函数


死锁现象

解释

集合中的每一个进程都在等待只能由本集合中的其他进程才能引发的事件,那么该组进程是死锁的

例如,如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象。

解决

  1. 对申请锁的内容设置超时时间

    • lock.acquire(timeout=2)
  2. semaphore

    • 允许一个资源最多由几个多线程同时使用
      • semaphore = threading.Semaphore(3) : 设置最多3个线程同时使用资源
  1. 可重入锁
    • lock = threading.RLock()
喜欢的可以对我打赏了哟~