【进程与线程】概念、threading、生产者消费者模型

程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程

程序和进程的区别:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念

进程的优点:提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。

进程的缺点

  • 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
  • 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行

 

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

 

io操作不占用CPU,计算占用CPU

python多线程不适合cpu密集操作型的任务,适合io操作密集型的任务

 

进程和线程的区别:

1.线程可以共享创建它的进程的地址空间;

   进程有它们各自的地址空间。

2.线程可以直接访问其进程的数据段;

   进程有自己的父进程的数据段副本。

3.线程可以直接与进程的其他线程通信;

   进程必须使用进程间通信与同级进程通信。

4.新线程很容易创建;

   新进程需要复制它的父进程。

5.线程可以控制同一进程的线程;

   进程只能对子进程进行控制。

6.对主线程的更改(取消、优先级更改等)可能会影响该进程的其他线程;

   对父进程的更改不会影响子进程。

 

GIL锁(全局解释器锁Global Interpreter Lock)

在CPython中,全局解释器锁是防止多个本机线程同时执行Python字节码的互斥体。主要是因为CPython的内存管理不是线程安全的。

GIL并不是Python的特性,Python完全可以不依赖于GIL,但是GIL是CPython的特点。

 

python threading模块:

import threading

def run1(n):
    print('threading',n)

if __name__ == '__main__':
    for i in range(50):
        t = threading.Thread(target=run1, args=(i,))#实例化一个线程
        t.start()    #启动线程
        print(t.getName())    #获取线程名

 Join & Daemon:

import threading,time

def runm1(n):
    print('threading',n)
    time.sleep(2)
    print('run thread done')

def main():
    for i in range(10):
        t = threading.Thread(target=run1, args=(i,))  # 实例化一个线程
        t.start()
        t.join(1)
        print('starting threading',t.getName())

if __name__ == '__main__':
    m = threading.Thread(target=main)#实例化一个线程
    m.setDaemon(True) #将main设置为守护线程,当主线程结束时,主线程的守护线程就会立即结束
    m.start()    #启动线程
    m.join(timeout=2) #等待线程执行结束
    print('main thread done')    #获取线程名

 线程锁(互斥锁Mutex)

import threading,time

def run1():
    global n
    time.sleep(1)
    lock.acquire()#修改数据前加锁
    n+=1
    lock.release()#修改后释放

n=0
thread_list=[]
lock=threading.Lock() #生成全局锁

if __name__ == '__main__':
    for i in range(100):
        t=threading.Thread(target=run1)
        t.start()
        thread_list.append(t)
    for t in thread_list:
        t.join()
        print('num:', n)

    print('final num:',n)

GIL和Lock:
GIL为系统级的lock,Lock是用户级的lock与GIL无关

RLock(递归锁)

大锁中包含子锁时,防止lock的释放混乱

import threading

def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num += 1
    lock.release()
    return num

def run2():
    print("grab the second part data")
    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)

if __name__ == '__main__':

    num, num2 = 0, 0
    lock = threading.RLock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)

 Semaphore(信号量)

 互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,与互斥锁用法相同。

import threading, time

def run(n):
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s\n" % n)
    semaphore.release()

if __name__ == '__main__':
    num = 0
    semaphore = threading.BoundedSemaphore(5)  # 实例化semaphore锁,最多允许5个线程同时运行
    for i in range(20):
        t = threading.Thread(target=run, args=(i,))
        t.start()

while threading.active_count() != 1:
    pass  # print threading.active_count()
else:
    print('----all threads done---')
    print(num)

 threading.Timer()

等待一定的时间调用函数

import threading

def hello(name):
    print('hello %s\n'%name)
    global timer
    timer = threading.Timer(2.0, hello, ["q1ang"])
    timer.start()

if __name__ == "__main__":
    timer = threading.Timer(2.0, hello, ["q1ang"])
    timer.start()

 Events

 通过Event来实现两个或多个线程间的交互

import threading
import time

event=threading.Event()#实例化

def lighter():
    count=0
    event.set() #设置标志位
    while True:
        if  count>20 and count<30:#改成红灯
            event.clear() #清除标志位
            print('红灯',count)
        elif count>30:
            event.set()    #设置标志位
            count=0
        else:
            print('绿灯',count)
        time.sleep(1)
        count+=1
        print()

def car(name):
    while True:
        if event.is_set():#判断标志位启动,(绿灯
            print('run')
            time.sleep(1)
        else:
            print('wait')
            event.wait() #等待设定标志位
            print('start runing...')

light=threading.Thread(target=lighter,)
light.start()

c1=threading.Thread(target=car,args=('Tesla',))
c1.start()

queue队列(解耦)线程queue

class queue.Queue(maxsize=0) #先入先出

class queue.LifoQueue(maxsize=0) #last in fisrt out 后入先出

class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

import queue

q=queue.Queue(maxsize=3)

q.put('d1')
q.put('d2')
q.put('d3')

print(q.qsize())

print(q.get(block=False,timeout=1))
print(q.get(block=False,timeout=1))
print(q.get(block=False,timeout=1))

 生产者消费者模型:解耦

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

import threading,time
import queue

q=queue.Queue(maxsize=10)

def Producer():
    count=1
    while True:
        q.put('包子%s'%count)
        print('生产了包子%s'%count)
        time.sleep(0.5)
        count+=1

def Consumer(name):
    while True:
        print('[%s]取到[%s]并吃了它...'%(name,q.get()))
        time.sleep(2)

p=threading.Thread(target=Producer)
c1=threading.Thread(target=Consumer,args=('consumer1',))
c2=threading.Thread(target=Consumer,args=('consumer2',))

p.start()
c1.start()
c2.start()

 

转载于:https://www.cnblogs.com/q1ang/p/9210689.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值