Python之路45-多线程

threading模块

线程有两种调用方式

直接调用

import threading
import time

def sayhi(num):     # 定义每个线程要执行的函数
    print("running on number:%s" % num)
    time.sleep(2)

if __name__ == "__main__":
    t1 = threading.Thread(target=sayhi, args=(1,))  # 生成一个线程实例
    t2 = threading.Thread(target=sayhi, args=(2,))  # 生成一个线程实例

    t1.start()  # 启动线程
    t2.start()  # 启动线程

    print(t1.getName())     # 获取线程名
    print(t2.getName())

继承式调用

import threading
import time

class MyThread(threading.Thread):

    def __init__(self, num):
        super(MyThread, self).__init__()
        self.num = num

    def run(self):  # 定义每个线程要运行的函数
        print("running on number:%s" % self.num)
        time.sleep(2)

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

并发的多线程示例

先看一段代码,启动十个线程,每个线程都会sleep2秒,我想计算下执行时间,预计是2秒左右

import threading
import time

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

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

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

use_time = time.time() - start_time
print("use time: ", use_time)

但是执行后发现,程序并没有等待我所以线程都执行完就打印了执行时间,这样不是我想要的结果,原因是主线程的执行操作,不会等待子线程执行完成,此处是不堵塞的,说到这里就引入了join,join是等待子线程执行

import threading
import time

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

start_time = time.time()    

t_list = []

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

for r in t_list:
    r.join()

use_time = time.time() - start_time
print("use time: ", use_time)

这样,主线程就能等待所以线程都执行结束再打印执行时间了,结果没有问题,use time:  2.0050017833709717

守护线程

主线程结束,守护线程不管执行没执行完它要做的操作都会跟着结束

import threading
import time

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

start_time = time.time()

for i in range(10):
    t = threading.Thread(target=run, args=(i,))
    t.setDaemon(True)   # 设置为守护线程
    t.start()

use_time = time.time() - start_time
print("use time: ", use_time)

通过setDaemon(True)设置此线程为守护线程,代码执行效果为主线程打印完使用时间程序就退出了,并没有sleep

线程锁(互斥锁)

一个进程可以启动多个线程,多个线程共享一块内存空间,也就意味着每个线程可以访问同一个数据,如果两个线程要同时修改同一份数据时,肯定会出问题

为了避免这样的问题,我们可以“加把锁”,也就是线程锁,同一时间只能让一个线程去修改这个数据

import threading

def run(n):
    lock.acquire()  # 加锁
    global num
    num += 1
    print(n)
    lock.release()  # 释放锁

lock = threading.Lock()    # 实例化一个互斥锁
num = 0

for i in range(1000):
    t = threading.Thread(target=run, args=("t-%s" % i,))
    t.start()

print("num:", num)

递归锁

一个大锁中还要有子锁

import threading

num1, num2 = 0, 0

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

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

def run3():
    lock.acquire()
    res1 = run1()
    print("-----between run1 and run2-----")
    res2 = run2()
    lock.release()
    print("res1:%s,res2:%s" % (res1, res2))

lock = threading.RLock()

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

while threading.active_count() != 1:
    pass
else:
    print("-----all threads done-----")
    print(num1, num2)

semaphore(信号量)

互斥锁同时允许一个线程更改数据,而信号量是同时允许一定数量的线程更改数据,比如厕所有3个坑,最多允许3个人上厕所,后面的人只能等有人出来才能进去上厕所

import threading
import time

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

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

event事件

通过事件可以实现两个或多个进程间的交互

import threading
import time
import random

def light():
    if not event.isSet():
        event.set()     # 设置标志,表示通行
    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 True:
        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):
        Car = threading.Thread(target=car, args=(i,))
        Car.start()

queue队列

程序解耦

加快执行速度

queue有几种模式

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

queue.LifoQueue(maxsize=0)    # 后入先出

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

先入先出的例子,取到1,2,3

import queue

q = queue.Queue()
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())

后入先出的例子,取到3,2,1

import queue

q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())

优先级的例子

import queue

q = queue.PriorityQueue()
q.put((2, "jack"))
q.put((3, "tom"))
q.put((1, "jiachen"))
print(q.get())
print(q.get())
print(q.get())

q.qsize()为队列中有几个数据

q.empty()判断队列中是否为空,空为True,非空为False

q.full()判断队列是否满了,满了为True,不满为False

q.put(item,block=True,timeout=None)将数据放入队列中

q.put_nowait(item)将数据放入队列中,如果队列满了,不堵塞直接报异常

q.get(item,block=True,timeout=None)取出队列中的数据,block为True如果没有数据可以取就堵塞,为False如果没有数据可以取就报异常,timeout为超时时间,超出时间报异常

q.get_nowait(item)取出队列中的数据,如果没有数据,不堵塞直接报异常

q.task_done()

q.join() 堵塞直到队列被消费完

生产者消费者模型

一个简单的例子

import queue
import threading
import time

def producer(name):
    count = 1
    while True:
        q.put(count)
        print("[%s]生产了骨头[%s]" % (name, count))
        count += 1
        time.sleep(0.5)

def consumer(name):
    while True:
        q.get()
        print("[%s]吃了根骨头" % name)
        time.sleep(1)

if __name__ == "__main__":
    q = queue.Queue(5)
    p = threading.Thread(target=producer, args=("xxx",))
    c1 = threading.Thread(target=consumer,args=("tom",))
    c2 = threading.Thread(target=consumer,args=("jack",))
    p.start()
    c1.start()
    c2.start()
时间: 2024-10-10 00:58:47

Python之路45-多线程的相关文章

【Rollo的Python之路】多线程实例 Join 与Daemon

1.0 threading 的join方法就是用来阻塞用的,可以阻塞主线程,等待所的子线程结束后,然后再运行后面的程序: import threading import time from time import ctime,sleep def music(func): for i in range(2): print("I was listening to %s.%s" %(func,ctime())) sleep(1) print("end listening %s&qu

Python之路【第十七篇】:Django【进阶篇 】

Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')

Python之路【第九篇】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached基于一个存储键/值对的hashmap.其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信. Memc

Python之路【第三篇】:Python基础(二)

Python之路[第三篇]:Python基础(二) 内置函数 一 详细见python文档,猛击这里 文件操作 操作文件时,一般需要经历如下步骤: 打开文件 操作文件 一.打开文件 1 文件句柄 = file('文件路径', '模式') 注:python中打开文件有两种方式,即:open(...) 和  file(...) ,本质上前者在内部会调用后者来进行文件操作,推荐使用 open. 打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作.

Python之路【第七篇】:线程、进程和协程

Python之路[第七篇]:线程.进程和协程 Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time   def show(arg):     time.sleep(1)     print 'thread'+str(arg)   for i in

Python之路【第六篇】:socket

Python之路[第六篇]:socket Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Unix,而Unix/Linux基本哲学之一就是"一切皆文件",对于文件用[打开][读写][关闭]模式来操作.socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO.打开.关闭

Python之路【第十五篇】:Web框架

Python之路[第十五篇]:Web框架 Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #!/usr/bin/env python #coding:utf-8   import socket   def handle_request(client):     buf = client.recv(10

Python之路_Day10

Python之路_Day10_课堂笔记 上节回顾: socket: 1.导入模块 2.创建socket 3. 字节 send:每次发送可能没有完全发送,send发送后会有一个返回值,是本次发送了多少. sendall:循环发送,直到全部发送完全. 接收 recv(2048):最多可以接收2048字节,上传文件时需要注意 粘包: socketserver: 1.自定义类 2.继承socketserver.BaseRequestHandler类 3.重写handle方法 4.socketserver

七日Python之路--第五天(之找点乐子)

(一)一些闲言碎语 刚才在搜索的时候,看到别人说的一句话,大体意思如下:自从学习Python之后,就不想在学习其他语言了,只想抓紧时间写些有用的东西.细想一下,果真如此. 唉,Python魅力如此之大.感觉比Java容易的多,也可能是小众语言,因为足够小才显得足够强大.算了,不愿多想,还是多写些有意思的东西吧,哈哈. (二)一些有趣的代码 (1)一句话文件服务器 [email protected]:~$ python -m SimpleHTTPServer Serving HTTP on 0.0

Python之路【第十七篇】:Django之【进阶篇】

Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')