python3 多线程

进程——资源分配的最小单位,线程——程序执行的最小单位

什么是进程?  

  程序的执行实例称为进程。每个进程都提供执行程序所需的资源。一个进程有一个虚拟地址空间,可执行代码,打开系统对象的句柄,安全上下文,一个独特的过程,pid标识符,环境变量,优先级类,最小和最大工作集大小,并且至少有一个执行线程。每个进程都是从一个线程开始的,通常被称为主主线程,但是可以创建额外的任何线程的线程。

进程与线程的区别?

  线程共享内存空间,进程的内存是独立的,同一个进程的线程之间可以直接交流,两个进程想通信,必须通过一个中间代理来实现,创建新线程很简单, 创建新进程需要对其父进程进行一次克隆,一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程

线程基本函数,

run() 里面是需要执行的命令,

start() 线程启动函数,

join() 等待该线程结束,

setDaemon(True) 设置为守护线程,设置守护线程需要放在线程启动前

Lock() 线程锁,防止数据的不准确行,线程执行时添加互斥锁

RLock() 递归锁,多个线程时需要添加递归锁,否则会出现锁死

BoundedSemaphore() 信息量,允许同时执行的最大线程数

threading.current_thread() ,当前线程;

threading.active_count() 目前活跃的线程数

1.简单线程的写法:

import threading
from time import sleep

'''多线程 第一种写法'''
def run(t):
    print("task-%s" %t)
    sleep(2)
    print("task-%s is done" %t)

t1 = threading.Thread(target=run,args=("t1",)) #参数后面需要带逗号,不然会误解析为一个参数
t2 = threading.Thread(target=run,args=("t2",))
t1.start()
t2.start()

'''多线程 第二种写法'''
class MyThread(threading.Thread):
    def __init__(self,t):
        super(MyThread, self).__init__()  #继承父类的init函数
        self.t = t

    def run(self):
        print("task-%s"%self.t)
        sleep(2)
        print("task-%s is done"%self.t)

if __name__ == "__main__":
    t1 = MyThread("t1")
    t2 = MyThread("t2")
    t1.start()
    t2.start()

'''多线程 第三种写法'''
def run(t):
    print("task-%s" % t)
    sleep(2)
    print("task-%s is done" % t)

for i in range(2):
    t = threading.Thread(target=run, args=("t1",)) # 参数后面需要带逗号,不然会误解析为一个参数
    t.start()

  这三种的运行结果都一样:

task-t1
task-t1
task-t1 is done
task-t1 is done

Process finished with exit code 0

2.计算所有线程运行的时间

import threading
import time

'''多计算所有线程运行的时间,这里需要给每个线程添加join'''
def run(t):
    print("task-%s" % t)
    time.sleep(2)
    print("task-%s is done" % t)

st_time = time.time() #开始时间

tups = [] #所有的线程对象列表
for i in range(2):
    t = threading.Thread(target=run, args=("t1",)) # 参数后面需要带逗号,不然会误解析为一个参数
    t.start()
    tups.append(t)

#所有线程启动后,添加join,等待结束后,主线程再继续
for i in tups:
    i.join()

print(time.time()-st_time) #需要时间

  运行结果:

task-t1
task-t1
task-t1 is done
task-t1 is done
2.0008037090301514

Process finished with exit code 0

3.设置守护线程

import threading
import time

'''程序本身就是主线程,守护线程是伴随主线程存在的,主线程关闭是不会等待守护线程,同时守护线程也会关闭'''
def run(t):
    print("task-%s" % t)
    time.sleep(2)
    print("守护线程:", threading.current_thread())
    print("task-%s is done" % t)

st_time = time.time() #开始时间

tups = [] #所有的线程对象列表
for i in range(10):
    t = threading.Thread(target=run, args=(i,)) # 参数后面需要带逗号,不然会误解析为一个参数
    t.setDaemon(True)  #设置为守护线程
    t.start()

print("主线程:",threading.current_thread())
print("运行时间",time.time()-st_time) #需要时间

  运行结果:

task-0
task-1
task-2
task-3
task-4
task-5
task-6
task-7
task-8
task-9主线程:
 <_MainThread(MainThread, started 6800)>
运行时间 0.0

Process finished with exit code 0

 3.子线程的相互交互

同一个进程里面的线程共享同一块空间,可以共享内存中的资源
由于python的多线程基于GIL(全局解释器锁)原理,是通过单核上下文切换实现的多线程 ,所以在多个子线程同时修改一个数据时,会存在这个还没改完就切换的情况,当时数据不准确,因此我们需要给每个子线程的操作加上线程锁(互斥锁),每次执行先获取锁,执行完释放锁;但是加上锁后其实就不是多线程执行了,而是变成串行(一个一个的执行),在所中间加上sleep()就可以看出效果

import threading,time

num = 0
lock = threading.Lock()
def run():
    lock.acquire()  #获取锁
    global num #声明全局变量
    time.sleep(1)
    num += 1
    print(num,time.time())
    lock.release()  #释放锁

for i in range(10):
    t = threading.Thread(target=run)
    t.start()

print(num)

  运行结果:

0
1 1542440306.993258
2 1542440307.99377
3 1542440308.9952087
4 1542440309.9967873
5 1542440310.9977813
6 1542440311.9988816
7 1542440312.9992244
8 1542440314.000361
9 1542440315.001824
10 1542440316.002374

Process finished with exit code 0

 4.递归锁

threading.RLock()为递归锁,当添加多个锁的时候就应该用递归锁,不然程序会锁死,成为死循环

import threading

def run1():
    print("grab the first part data")
    rlock.acquire() #第二次加锁 内层锁
    global num
    num += 1
    rlock.release()  #释放内层锁
    return num

def run2():
    print("grab the second part data")
    rlock.acquire()
    global num2
    num2 += 1
    rlock.release()
    return num2

def run3():
    rlock.acquire() #第一次加锁, 最外层锁
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    rlock.release() #释放最外层锁
    print(res, res2)

if __name__ == '__main__':
    num, num2 = 0, 0
    rlock = threading.RLock()
    for i in range(5):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:  #判断子线程是否执行完
    print(threading.active_count())  #递归锁
else:
    print('----all threads done---')
    print(num, num2)

  运行结果:

grab the first part data
--------between run1 and run2-----
grab the second part data
1 1
grab the first part data
--------between run1 and run2-----
grab the second part data
2 2
grab the first part data2
2
2
--------between run1 and run2-----
grab the second part data
3 3

----all threads done---
3 3

Process finished with exit code 0

  5.信息量

互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去,从运行结果来看5个线程同时运行的。

import threading,time

num = 0
semaphore = threading.BoundedSemaphore(5)  #信息量, 同时最多允许5个线程
def run():
    semaphore.acquire()  #获取信息量
    global num #声明全局变量
    time.sleep(1)
    num += 1
    print(num,time.time())
    semaphore.release()  #释放信息量

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

print(num)

  运行结果:

0
1 1542440702.8448975
2 1542440702.845902
3 1542440702.845902
4 1542440702.845902
5 1542440702.8469012

6 1542440703.8459327
7 1542440703.846936
8 1542440703.846936
9 1542440703.847937
10 1542440703.847937

11 1542440704.847123
12 1542440704.848123
13 1542440704.848123 
14 1542440704.8491254
15 1542440704.8491254

16 1542440705.8484023
17 1542440705.8494039
18 1542440705.8494039
19 1542440705.8504024
20 1542440705.8504024

Process finished with exit code 0

  6.python自带的队列 Queue()  LifoQueue()  PriorityQueue()

import queue
''' python自带的队列  '''
q = queue.Queue() #先入先出
lq = queue.LifoQueue() #后进先出  (用法同Queue())

q.put(1,block=True,timeout=1)  #block=True 没有数据会锁死,False不会锁死, timeout 超时时间
q.put(2)
q.put(3)
print("Queue()大小:", q.qsize())  # 队列中的大小
for i in range(3):
    q1 = q.get(block=True,timeout=2)  #block=True 没有数据会锁死,False不会锁死, timeout 超时时间
    print(q1)

pq = queue.PriorityQueue()  #根据优先级进出
pq.put(5,'jiad')
pq.put(-2,'ieamd')
pq.put(9,'bmoad')
print("PriorityQueue()大小:", pq.qsize())  # 队列中的大小
for i in range(3):
    pq1 = pq.get(block=True,timeout=2)  #block=True 没有数据会锁死,False不会锁死, timeout 超时时间
    print(pq1)

  运行结果:

Queue()大小: 3
1
2
3
PriorityQueue()大小: 3
-2
5
9

  通过队列实现生产者消费者关系

import threading,time,queue

q = queue.Queue(maxsize=10)

def Producer(name):
    '''  生产者 '''
    count = 1
    while True:
        q.put("酱骨头%s"%count)
        print("已经生产的数量:",count)
        time.sleep(2)
        count +=1

def Consumer(name):
    while True:
        while q.qsize()>0:
            print("%s取到了%s,并且吃了它"%(name,q.get()))
            time.sleep(1)

p = threading.Thread(target=Producer,args=("张三",))
c1 = threading.Thread(target=Consumer,args=("李四",))
c2 = threading.Thread(target=Consumer,args=("王五",))
p.start()
c1.start()
c2.start()

  7.event 事件,可以设置标志位(event.set()),清空标识位(event.clear()),等待(event.wait()) 是否存在标识位event.is_set()

import threading,time

event = threading.Event()
def lighter():
    ''' 模拟红绿灯 10秒钟绿灯,10秒钟红灯 有标识位表示绿灯,没有表示红灯'''
    count = 0  # 时间长度
    event.set()  # 设置标识位
    while True:
        if count>10 and count<=20: #红灯
            event.clear()  # 把标志位清了
            print("\033[31;1m红灯.STOP...\033[0m")
        elif count >20 :
            event.set()  # 设置标志位
            count = 0  #清零
        else:
            print("\033[36;1m绿灯.RUN...\033[0m")
        time.sleep(1)
        count += 1

def car(name):
    ''' 汽车的线程 '''
    while True:
        if event.is_set(): #存在标识位
            print("%s is run..."%name)
            time.sleep(1)
        else:
            print("红灯需要等待...")
            event.wait()

lt = threading.Thread(target=lighter,)
lt.start() #红绿灯的线程

ct = threading.Thread(target=car,args=("Tesla",))
ct.start() #汽车的线程

  

 

 

 

  

 

posted @ 2018-11-15 16:48  CansonHai  阅读(349)  评论(0编辑  收藏  举报