11.python线程

基本概念

1.进程

      定义:  进程就是一个程序在一个数据集上的一次动态执行过程。安全

  组成:  进程通常由程序、数据集、进程控制块三部分组成。多线程

  程序:  咱们编写的程序用来描述进程要完成哪些功能以及如何完成;并发

  数据集: 则是程序在执行过程当中所须要使用的资源;app

  进程控制块: 用来记录进程的外部特征,描述进程的执行变化过程,系统能够利用它来控制和管理进程,它是系统感知进程存在的惟一标志异步

2.线程

       线程的出现是为了下降上下文切换的消耗,提升系统的并发性,并突破一个进程只能干同样事的缺陷,使到进程内并发成为可能。ide

  线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程当中的最小单元函数

    组成:由线程ID、程序计数器、寄存器集合和堆栈共同组成。post

  线程的引入减少了程序并发执行时的开销,提升了操做系统的并发性能。线程没有本身的系统资源性能

3.线程与进程的区别

  1. 线程是执行的指令集 , 进程是资源的集合
  2. 线程的启动速度要比进程的启动速度要快
  3. 两个线程的执行速度是同样的
  4. 进程与线程的运行速度是没有可比性的
  5. 线程共享建立它的进程的内存空间 , 进程的内存是独立的
  6. 两个线程共享的数据都是同一份数据 , 两个子进程的数据不是共享的 , 并且数据是独立的
  7. 同一个进程的线程之间能够直接交流 , 同一个主进程的多个子进程之间是不能够进行交流 , 若是两个进程之间须要通讯 , 就必需要经过一个中间代理来实现
  8. 一个新的线程很容易被建立 , 一个新的进程建立须要对父进程进行一次克隆
  9. 一个线程能够控制和操做同一个进程里的其余线程 , 线程与线程之间没有隶属关系 , 可是进程只能操做子进程
  10. 改变主线程 , 有可能会影响到其余线程的行为 , 可是对于父进程的修改是不会影响子进程

4.同步和异步

        同步就是指一个进程在执行某个请求的时候,若该请求须要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;ui

     异步是指进程不须要一直等下去,而是继续执行下面的操做,无论其余进程的状态。当有消息返回时系统会通知进程进行处理,这样能够提升执行的效率。

       举个例子,打电话时就是同步通讯,发短息时就是异步通讯

5.并行和并发

        并行指系统具备处理多个任务(动做)的能力

       并发是指系统具备同时处理多个任务(动做)的能力

 6.阻塞与非阻塞

        阻塞调用是指调用结果返回以前,当前线程会被挂起(如遇到io操做)。函数只有在获得结果以后才会将阻塞的线程激活。

        非阻塞和阻塞的概念相对应,指在不能马上获得结果以前也会马上返回,同时该函数不会阻塞当前线程

 

线程threading模块

import threading
import time

def run(n):         #定义线程要运行的函数
    print('task',n)
    time.sleep(2)

if __name__ == '__main__':
    t1 = threading.Thread(target=run,args=(1,))          #生成一个线程
    t2 = threading.Thread(target=run,args=(2,))
    t1.start()
    t2.start()

print('I am main thread')                #主线程

#这个进程里面有三个线程,1个主线程,t1,t2两个子线程
#子线程和主线程是同步开启的,主线程结束后,要等子线程所有结束后,进程才会关闭
函数调用
import threading,time

class MyThread(threading.Thread):   #继承threading,Thread模块
    def __init__(self,n):
        super(MyThread, self).__init__()    #继承父类
        self.n = n

    def run(self):                 #必须用run
        print('task',self.n)
        time.sleep(2)

t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()

print('I am main thread')
print(t1.is_alive())       #返回线程是否活动的。
print(t1.getName())        #返回线程名。
t1.setName('我是T1')       #设置线程名。
print(t1.getName())
print(threading.currentThread())     #查看当前线程是主线程(mainThread)仍是子线程(Thread)
print(threading.activeCount())       #返回正在运行的线程数量


结果:
task 1
task 2
I am main thread
True
Thread-1
我是T1
<_MainThread(MainThread, started 9580)>
3

Process finished with exit code 0
类继承调用

join和setDaemon

主线程 : 当一个程序启动时 , 就有一个进程被操做系统建立 , 与此同时一个线程也马上运行 , 该线程一般叫作程序的主线程

子线程 : 由于程序是开始时就执行的 , 若是你须要再建立线程 , 那么建立的线程就是这个主线程的子线程

join的做用:是保证当前线程执行完成后,再执行其它线程

import threading
import time

def run(n):
    print("task ",n )
    time.sleep(2)

start_time = time.time()
t_objs = []    #存线程实例

for i in range(50):        #生成50个线程
    t = threading.Thread(target=run,args=("t-%s" %i ,))
    t.start()
    t_objs.append(t)  #为了避免阻塞后面线程的启动,不在这里join,先放到一个列表里

for t in t_objs:      #循环线程实例列表,等待全部线程执行完毕
    t.join()

print("---all threads has finished...")
print("cost:",time.time() - start_time)
join

setDaemon

将线程声明为守护线程,必须在start() 方法调用以前设
setDaemon(),只要主线程完成了,无论子线程是否完成,都要和主线程一块儿退出
import threading
import time

def run(n):
    print('task',n)
    time.sleep(2)
    print('i am 子线程')     #主线程结束,setDaemon无论有没有运行完都会被销毁

if __name__ == '__main__':
    t1 = threading.Thread(target=run,args=(1,))
    t2 = threading.Thread(target=run,args=(2,))
    t1.setDaemon(True)   #设置守护线程,放在start以前
    t1.start()
    t2.setDaemon(True)
    t2.start()

print('I am main thread')


结果:
task 1
task 2
I am main thread
setDaemon

线程锁(互斥锁Mutex)

lock:若是有多个进程对同一文件进行修改 , 就会形成错乱 , 因此咱们为了保护文件数据的安全 , 就须要给其进行加锁,join为总体串行 , lock为局部串行

Rlock:在线程间共享多个资源的时候,若是两个线程分别占有一部分资源而且同时等待对方的资源,就会形成死锁,由于系统判断这部分资源都正在使用,全部这两个线程在无外力做用下将一直等待下去。

           Rlock就是解决死锁的问题。

import time
import threading

def addNum():
    global num #在每一个线程中都获取这个全局变量
    print('--get num:',num )
    time.sleep(1)
    lock.acquire() #修改数据前加锁
    num  -=1 #对此公共变量进行-1操做
    lock.release() #修改后释放

num = 100  #设定一个共享变量
thread_list = []
lock = threading.Lock() #生成全局锁
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list: #等待全部线程执行完毕
    t.join()

print('final num:', num )
lock
import threading, time


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:      1
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)
Rlock

semaphore(信号量)

import threading, time

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

if __name__ == '__main__':
    semaphore = threading.BoundedSemaphore(5)  # 最多容许5个线程同时运行
    for i in range(22):
        t = threading.Thread(target=run, args=(i,))
        t.start()
while threading.active_count() != 1:
    pass
else:
    print('----all threads done---')
semaphore

queue(队列)

import queue
#queue
#主要做用:解耦
 #         提升运行效率

q =queue.Queue()    #生成一个队列对象   先入先出
q.put('1')          #put item into the queue
q.put('2')
q.put('3')

q.qsize()          #看队列大小
q.get()            #从队列中取

q.get(block=True, timeout=None)  #取不到数据,默认阻塞,timeout设置阻塞时间
q.get_nowait()      #若是队列为空,取不到数据,抛出异常,不会阻塞卡主
q = queue.Queue(maxsize=3)         #maxsize能够设置队列的大小,最多容许存三个
q = queue.PriorityQueue           #优先级
print(q.full())       #判断队列是否有数据  返回blue值
print(q.empty())      #判断队列是不是空    返回blue值
queue用法

生产者消费者模型

为何要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,若是生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。一样的道理,若是消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题因而引入了生产者和消费者模式。

什么是生产者消费者模式

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

import threading,time
import queue

q = queue.Queue(maxsize=5)       #设置maxsize=5,防止生产过快

def Producer(name):    #生产者
    count = 1
    while True:
        q.put("面包%s" % count)
        print("%s生产了面包%s"%(name,count))
        count +=1
        time.sleep(0.1)

def  Consumer(name):         #消费者
    while True:
        print("[%s] 取到[%s] 而且吃了它..." %(name, q.get()))
        time.sleep(1)

#生成多个线程
p = threading.Thread(target=Producer,args=("derek",))
c = threading.Thread(target=Consumer,args=("chihuo1",))
c1 = threading.Thread(target=Consumer,args=("chihou2",))

p.start()
c.start()
c1.start()
View Code

Events

 event = threading.Event()

# a client thread can wait for the flag to be set
event.wait()

# a server thread can set or reset it
event.set()
event.clear()

If the flag is set, the wait method doesn’t do anything.
If the flag is cleared, wait will block until it becomes set again.
Any number of threads may wait for the same event.

import time
import threading

event = threading.Event()

def lighter():     #红绿灯
    count = 0
    event.set()     #set flag 初始绿灯
    while True:
        if count >5 and count < 10: #改为红灯
            event.clear() #把标志位清了
            print("如今是红灯")
        elif count >10:
            event.set() #变绿灯
            count = 0
        else:
            print("如今是绿灯")
        time.sleep(1)
        count +=1

def car(name):
    while True:
        if event.is_set():   #判断the flag 是否is set 表明绿灯
            print("[%s] running..."% name )
            time.sleep(1)
        else:
            print("[%s] waiting ...... " %name)
            event.wait()   #等flag被set
            print("绿灯亮了,%s能够走了" %name)
            time.sleep(1)



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

car1 = threading.Thread(target=car,args=("Tesla",))
car1.start()
红绿灯
相关文章
相关标签/搜索