python 多线程

进程、线程之间的关系

打个比方:如果有一个车间,车间里面有工人在工作。那么进程就相当于这个车间,而线程就相当于车间里面工作的工人。
是不是差不多明白点了。进程不能运行,它是一些资源的封装体,主要是cpu,io,内存资源,好比车间里的电和工具一样。每个进程要运行至少需要一个线程,这个线程就是主线程。线程是负责干具体的工作的。

单线程的例子:
import time
def eat(food):
    print ("eat %s" %food)
    print("start:", time.ctime())
    time.sleep(2)
    print (time.ctime())

def play(name):
    print ("play %s" %name)
    time.sleep(5)
    print (time.ctime())

if __name__=="__main__":
    eat("宫保鸡丁")
    play("篮球")
    print (time.ctime())
结果:
    eat 宫保鸡丁
    start: Wed Nov 29 21:05:26 2017
    Wed Nov 29 21:05:28 2017
    play 篮球
    Wed Nov 29 21:05:33 2017
    Wed Nov 29 21:05:33 2017

定义一个吃和玩的例子。可以看到,程序的运行的总时间是等于所以时间之和。

多线程例子:
import time
import threading
def eat(food):
    print ("eat %s" %food)
    print ("start:",time.ctime())
    time.sleep(2)
    print ("eat",time.ctime())

def play(name):
    print ("play %s" %name)
    time.sleep(5)
    print ("play",time.ctime())


t1 = threading.Thread(target=eat,args=("宫保鸡丁",))
t2 = threading.Thread(target=play,args=("篮球",))


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

    print ("main:",time.ctime())

结果:
    eat 宫保鸡丁
    start: Wed Nov 29 20:58:48 2017
    play 篮球
    main: Wed Nov 29 20:58:48 2017
    eat Wed Nov 29 20:58:50 2017
    play Wed Nov 29 20:58:53 2017

可以看出,对比单线程。时间减少了2秒。
多线程的定义:

  • 导入threading类
  • t1 = threading.Thread(target=eat,args=(“宫保鸡丁”,)) 实例化Thread 类。target= 传入要执行的函数,args= 函数的参数。是一个元组。注意后面的逗号
  • t1.start() 运行这个线程
setDaemon守护线程
def eat(food):
    print ("eat %s" %food)
    time.sleep(2)
    print ("eat",time.ctime())

def play(name):
    print ("play %s" %name)
    time.sleep(5)
    print ("play",time.ctime())

threads = []
t1 = threading.Thread(target=eat,args=("宫保鸡丁",))
threads.append(t1)
t2 = threading.Thread(target=play,args=("篮球",))
threads.append(t2)


if __name__=="__main__":
    t1.setDaemon(True)
    t1.start()
    t2.setDaemon(True)
    t2.start()
    print ("main:",time.ctime())
 结果:
    eat 宫保鸡丁
    play 篮球
    main: Thu Nov 30 09:46:38 2017

setDaemon是守护线程,就是守护着主线程。主线程退出子线程就跟着退出。
注意:setDaemon 在start之前

join等待子线程运行完再运行主线程

def eat(food):
    print ("eat %s" %food)
    time.sleep(2)
    print ("eat",time.ctime())

def play(name):
    print ("play %s" %name)
    time.sleep(5)
    print ("play",time.ctime())

threads = []
t1 = threading.Thread(target=eat,args=("宫保鸡丁",))
threads.append(t1)
t2 = threading.Thread(target=play,args=("篮球",))
threads.append(t2)
if __name__=="__main__":
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    print ("main:",time.ctime())
结果:
eat 宫保鸡丁
play 篮球
eat Thu Nov 30 09:48:21 2017
play Thu Nov 30 09:48:24 2017
main: Thu Nov 30 09:48:24 2017

可以看到主线程的main 最后执行。这里用循环,让两个子线程同时运行,运行完毕再运行主线程

内存共享 + 线程锁

num = 1
threads = []
lock = threading.Lock()
def add_num():
    global num
    lock.acquire()
    num +=1
    lock.release()
    time.sleep(1)

for i in range(500):
    t = threading.Thread(target=add_num)
    t.start()
    threads.append(t)

for t in threads:
    t.join()
print (num)
结果:
    501

内存共享是线程的一个特点,就是多个线程可以修改同一个内存数据。但是有时候会可能多个线程同时修改一个数据造成数据的不正确(在python2中出现过,不多。python3 没有出现)。为了保险起见可以在修改数据之前加一个锁(threading.Lock())。修改之后再释放锁来保证数据不会同时被多个线程占用。

threading.Event 线程事件(引用博友的代码了,写的挺好)
import threading,time
import random
def light():
    if not event.isSet():
        event.set() #wait就不阻塞 #绿灯状态
    count = 0
    while True:
        if count < 10:
            print('\033[42;1m--green light on---\033[0m')
        elif count <13:
            print('\033[43;1m--yellow light on---\033[0m')
        elif count <20:
            if event.isSet():
                event.clear()
            print('\033[41;1m--red light on---\033[0m')
        else:
            count = 0
            event.set() #打开绿灯
        time.sleep(1)
        count +=1
def car(n):
    while 1:
        time.sleep(random.randrange(10))
        if  event.isSet(): #绿灯
            print("car [%s] is running.." % n)
        else:
            print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
    event = threading.Event()
    Light = threading.Thread(target=light)
    Light.start()
    for i in range(3):
        t = threading.Thread(target=car,args=(i,))
        t.start()

event = threading.Event() 实例化一个事件
event.isSet()判断是否为True
even.set() 设置为True
even.clear() 设置为False

我觉得event就是设置了一个全局变量,每个线程根据变量的真假做动作。上面代码改为全局变量模式

import threading,time
import random

flag = True
def light():
    global flag
    if not flag:
        flag = True #wait就不阻塞 #绿灯状态
    count = 0
    while True:
        if count < 10:
            print('\033[42;1m--green light on---\033[0m')
        elif count <13:
            print('\033[43;1m--yellow light on---\033[0m')
        elif count <20:
            if flag:
                flag = False
            print('\033[41;1m--red light on---\033[0m')
        else:
            count = 0
            flag=True #打开绿灯
        time.sleep(1)
        count +=1
def car(n):
    global flag
    while 1:
        time.sleep(random.randrange(10))
        if  flag: #绿灯
            print("car [%s] is running.." % n)
        else:
            print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
    #event = threading.Event()
    Light = threading.Thread(target=light)
    Light.start()
    for i in range(3):
        t = threading.Thread(target=car,args=(i,))
        t.start()
多线程加queue实现生产者消费者模型。

模型简介:
生产者生产包子,消费者吃包子。如果生产者生产的慢,消费者吃得快。就会导致消费者的等待,在等待的过程中不能干别的事情。所以引入了queue,它就像一个桌子一样,生产完包子将包子放到桌子上,消费者直接去桌子上取。这样消费者不直接依赖生产者,也就实现了解耦。
上代码:

import queue
import threading
import time
q = queue.Queue()
def producer(name):
    while True:
        time.sleep(1)
        q.put("包子")
        print ("%s 做了一个包子" %name)
        print (q.qsize())

def comsumer(name):
    while True:
        time.sleep(2)
        if not q.empty():
            q.get()
            print("%s 吃了一个包子" %name)
for i in range(2):
    t = threading.Thread(target=producer,args=("大壮",))
    t.start()
for i in range(3):
    t = threading.Thread(target=comsumer,args=("小壮实",))
    t.start()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值