Python - 进程与线程

进程和线程

进程之间的通信: q = multiprocessing.Queue()
进程池之间的通信: q = multiprocessing.Manager().Queue()
线程之间的通信: q = queue.Queue()

功能

进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
线程,能够完成多任务,比如 一个QQ中的多个聊天窗口

定义的不同

进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源

区别

一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
线程不能够独立执行,必须依存在进程中

优缺点

线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反

互斥锁

当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
互斥锁为资源引入一个状态:锁定/非锁定。
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
threading模块中定义了Lock类,可以方便的处理锁定:

#创建锁    
mutex = threading.Lock()
#锁定
mutex.acquire([blocking])
#释放
mutex.release()

多线程-非共享数据

对于多线程中全局变量和局部变量是否共享

多线程局部变量

    #coding=utf-8
    import threading
    import time

    class MyThread(threading.Thread):
          # 重写 构造方法
          def __init__(self,num,sleepTime):
                  threading.Thread.__init__(self)
                  self.num = num
                  self.sleepTime = sleepTime

          def run(self):
                  self.num += 1
                  time.sleep(self.sleepTime)
                  print('线程(%s),num=%d'%(self.name, self.num))

    if __name__ == '__main__':
          mutex = threading.Lock()
    t1 = MyThread(100,5)
    t1.start()
    t2 = MyThread(200,1)
    t2.start()

运行结果:

线程(Thread-2),num=201
线程(Thread-1),num=101

多线程全局变量

import threading
from time import sleep
def test(sleepTime):
      num = 1
      sleep(sleepTime)
      num+=1
      print('---(%s)--num=%d'%(threading.current_thread(), num))
if __name__ == '__main__':
      t1 = threading.Thread(target = test,args=(5,))
      t2 = threading.Thread(target = test,args=(1,))

t1.start()
t2.start()

运行结果:

---()--num=2
---()--num=2

在多线程开发中,全局变量是多个线程都共享的数据,而局部变量等是各自线程的,是非共享的

同步应用

多个线程有序执行

from threading import Thread,Lock
from time import sleep
class Task1(Thread):
    def run(self):
        while True:
            if lock1.acquire():
                print("------Task 1 -----")
                sleep(0.5)
                lock2.release()
class Task2(Thread):
    def run(self):
        while True:
            if lock2.acquire():
                print("------Task 2 -----")
                sleep(0.5)
                lock3.release()
class Task3(Thread):
    def run(self):
        while True:
            if lock3.acquire():
                print("------Task 3 -----")
                sleep(0.5)
                lock1.release()

使用Lock创建出的锁默认没有“锁上”

lock1 = Lock()

创建另外一把锁,并且“锁上”

lock2 = Lock()
lock2.acquire()

创建另外一把锁,并且“锁上”

lock3 = Lock()
lock3.acquire()
t1 = Task1()
t2 = Task2()
t3 = Task3()
t1.start()
t2.start()
t3.start()

运行结果:

------Task 1 -----
------Task 2 -----
------Task 3 -----
------Task 1 -----
------Task 2 -----
------Task 3 -----
------Task 1 -----
------Task 2 -----
------Task 3 -----
------Task 1 -----
------Task 2 -----
------Task 3 -----
------Task 1 -----
------Task 2 -----
------Task 3 -----
------Task 1 -----
------Task 2 -----
------Task 3 -----
------Task 1 -----
------Task 2 -----
------Task 3 -----
...........`

可以使用互斥锁完成多个任务,有序的进程工作,这就是线程的同步

生产者与消费者模式

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语(可以理解为原子操作,即要么不做,要么就做完),能够在多线程中直接使用。可以使用队列来实现线程间的同步。

  • 用FIFO队列实现上述生产者与消费者问题的代码如下:
import threading,time
from queue import Queue
class Producer(threading.Thread):
    def run(self):
        global queue
        count = 0
        while True:
            if queue.qsize() < 1000:
                for i in range(100):
                    count = count +1
                    msg = '生成产品'+str(count)
                    queue.put(msg)
                    print(msg)
            time.sleep(0.5)
class Consumer(threading.Thread):
    def run(self):
        global queue
        while True:
            if queue.qsize() > 100:
                for i in range(3):
                    msg = self.name + '消费了 '+queue.get()
                    print(msg)
            time.sleep(1)
if __name__ == '__main__':
    queue = Queue()
    for i in range(500):
        queue.put('初始产品'+str(i))
    for i in range(2):
        p = Producer()
        p.start()
    for i in range(5):
        c = Consumer()
        c.start()

运行结果:

生成产品1
生成产品2
生成产品1
生成产品3
生成产品2
生成产品4
Thread-3消费了 初始产品0
生成产品3
生成产品5
Thread-3消费了 初始产品1
生成产品4
生成产品6
Thread-4消费了 初始产品2
Thread-3消费了 初始产品3
生成产品5
生成产品7
Thread-4消费了 初始产品4
生成产品6
生成产品8
Thread-5消费了 初始产品5
Thread-4消费了 初始产品6
...........

此时就出现生产者与消费者的问题

Queue的说明

1.对于Queue,在多线程通信之间扮演重要的角色
2.添加数据到队列中,使用put()方法
3.从队列中取数据,使用get()方法
4.判断队列中是否还有数据,使用qsize()方法

你可能感兴趣的:(Python - 进程与线程)