• Python 的thread模块是比较底层的模块,Python的threading模块是对thread做了一些包装,可以更加方便的

    被使用;

1. 使用threading 模块

# 示例一: 单线程执行
import time def say_happy():
print("Happy Birthday!")
time.sleep(2) if __name__ == "__main__":
for i in range(5):
say_happy() # 示例二: 多线程执行
import threading
import time def say_happy():
print("Happy Birthday!")
time.sleep(2) if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=say_happy)
t.start() # 启动线程,即让线程开始执行 # 示例三: 第二种创建多线程的方式
import threading
import time class MyThread(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self)
self.num = num def run(self): # 定义每个线程要运行的函数
print('running on number: %s' % self.num) time.sleep(3) if __name__ == '__main__':
t1 = MyThread(1)
t2 = MyThread(2)
t3 = MyThread(3)
t1.start()
t2.start()
t3.start()

2. 多线程之间共享全局变量

# 示例:
from threading import Thread
import time g_num = 100 def work1():
global g_num
for i in range(3):
g_num += 1 print("=== in work1, g_num is %d ===" % g_num) def work2():
global g_num
print("=== in work2, g_num is %d ===" % g_num) print("=== 线程创建之前g_num is %d ===" % g_num) t1 = Thread(target=work1)
t1.start() # 延时一会儿, 保证t1线程中的事情做完
time.sleep(1) t2 = Thread(target=work2)
t2.start() # 输出:
# === 线程创建之前g_num is 100 ===
# === in work1, g_num is 103 ===
# === in work2, g_num is 103 === # 示例二: 多线程共享变量的问题
from threading import Thread
import time g_num = 0 def test1():
global g_num
for i in range(1000000):
g_num += 1 print("=== test1 === g_num=%d" % g_num) def test2():
global g_num
for i in range(1000000):
g_num += 1 print("=== test2 === g_num=%d" % g_num) p1 = Thread(target=test1)
p1.start() # time.sleep(3) p2 = Thread(target=test2)
p2.start() print("=== g_num=%d" % g_num) # 输出:
# === g_num=281358
# === test1 === g_num=1477304
# === test2 === g_num=1531631 # 示例三: 列表当作实参传递到线程中
from threading import Thread
import time def work1(nums):
nums.append(44)
print("=== in work1 ===", nums) def work2(nums):
# 延时一会儿,保证t1线程中的事情做完
# 这里的参数,不需要使用 global 关键字
time.sleep(1)
print("=== in work2 ===", nums) g_nums = [11, 22, 33] t1 = Thread(target=work1, args=(g_nums,))
t1.start() t2 = Thread(target=work2, args=(g_nums,))
t2.start()

3. 互斥锁

# 示例:
from threading import Thread, Lock
import time g_num = 0 def test1():
global g_num
# 上锁
mutex.acquire()
for i in range(1000000):
g_num += 1 # 释放锁
mutex.release() print("=== test1 === g_num=%d" % g_num) def test2():
global g_num
mutex.acquire()
for i in range(1000000):
g_num += 1 # 释放锁
mutex.release() print("=== test2 === g_num=%d" % g_num) # 创建一把互斥锁
mutex = Lock() p1 = Thread(target=test1)
p1.start() p2 = Thread(target=test2)
p2.start() # 输出:
# === test1 === g_num=1000000
# === test2 === g_num=2000000

4. 死锁

# 示例
import threading
import time class MyThread1(threading.Thread):
def run(self):
if mutexA.acquire():
print(self.name + "=== do1 === up ===")
time.sleep(1) if mutexB.acquire():
print(self.name + "=== do1 === down ===")
mutexB.release()
mutexA.release() class MyThread2(threading.Thread):
def run(self):
if mutexB.acquire():
print(self.name + "=== do2 === up ===")
time.sleep(1) if mutexA.acquire():
print(self.name + "=== do2 === down ===")
mutexA.release()
mutexB.release() mutexA = threading.Lock()
mutexB = threading.Lock()
# lock = threading.RLock() # 递归锁(可重用锁) if __name__ == '__main__':
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()

5. 信号量(Semaphore)

  • 信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数器,每当调用acquire()

    时-1,调用release()时,+1;
  • 计数器不能小于0,当计数器为0时,acquire()将阻塞线程至同步锁定状态,直至其他线程调用release();
  • BoundedSemaphoreSemaphore的唯一区别在于前者将在调用release时,检查计数器的值是否超过了计

    数器的初始值,如果超过了将抛出一个异常;
# 示例:
import threading
import time class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release() if __name__ == '__main__':
semaphore = threading.BoundedSemaphore(5) # 创建信号量锁
thrs = []
for i in range(100):
thrs.append(myThread())
for t in thrs:
t.start()

6. 条件变量同步(Condition)

  • 有一类线程需要满足条件之后,才能够继续执行,Python提供了threading.Condition对象用于条件变量线程的支

    持,它除了能提供RLock()Lock()的方法外,还提供了wait(),notify(),notifyAll()方法;
  • wait(): 条件不满足时调用,线程会释放锁并进入等待阻塞;
  • notify(): 条件创造后调用,通知等待池激活一个线程;
  • notifyAll(): 条件创造后调用,通知等待池激活所有线程;
# 示例一:
lock_con = threading.Condition([Lock/Rlock]): 锁参数是可选选项,不传入锁,对象自动创建一个 RLock() # 示例二:
import threading
import time
from random import randint class Producer(threading.Thread):
def run(self):
global L
while True:
val = randint(0, 100)
print('生产者', self.name, ':Append' + str(val), L)
if lock_con.acquire():
L.append(val)
lock_con.notify()
lock_con.release()
time.sleep(3)
class Customer(threading.Thread):
def run(self):
global L
while True:
lock_con.acquire()
if len(L) == 0:
lock_con.wait()
print('消费者', self.name,':Delete'+str(L[0]), L)
del L[0]
lock_con.release()
time.sleep(0.25) if __name__ == '__main__':
L = []
lock_con = threading.Condition()
threads = []
for i in range(5):
threads.append(Producer())
threads.append(Customer())
for t in threads:
t.start()
for t in threads:
t.join()

7. 同步条件(Event)

  • 条件同步和条件变量同步差不多意思,只是少了锁功能,因为条件同步设计于不访问共享资源的条件环境。
  • event = threading.Event(): 条件环境对象,初始值为False;
  • event.isSet(): 返回event的状态值;
  • event.wait(): 如果 event.isSet() == False将阻塞线程;
  • event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态,等待操作系统调度;
  • event.clear(): 恢复event的状态值为False;
# 示例一:
import threading
import time
class Boss(threading.Thread):
def run(self):
print('Boss: 今晚大家都要加班到22:00')
event.isSet() or event.set()
time.sleep(5)
print('Boss: <22:00>可以下班了')
event.isSet() or event.set() class Worker(threading.Thread):
def run(self):
event.wait()
print('Worker: 哎.....命苦啊!')
time.sleep(0.25)
event.clear()
event.wait()
print('Worker: Oh Yeah!') if __name__ == '__main__':
event = threading.Event()
threads = []
for i in range(5):
threads.append(Worker())
threads.append(Boss())
for t in threads:
t.start()
for t in threads:
t.join() # 示例二: 红绿灯
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 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()

8. 生产者与消费者模式

# 示例:
from queue import Queue class Producer(threading.Thread):
def run(self):
global queue
count = 0
while True:
if queue.qsize() < 1000:
for i in range(100):
count = count + 1
msg = "生成产品" + str(count)
queue.put(msg)
time.sleep(0.5) class Consumer(threading.Thread):
def run(self):
global queue
while True:
if queue.qsize() > 100:
for i in range(3):
msg = self.name + "消费了" + queue.get()
print(msg)
time.sleep(1) if __name__ == '__main__':
queue = Queue() for i in range(500):
queue.put("初始产品"+str(i))
for i in range(2):
p = Producer()
p.start()
for i in range(5):
c = Consumer()
c.start()

9. ThreadLocal 对象在线程中的使用

# 示例:
import threading # 创建全局 ThreadLocal 对象
local_school = threading.local() def process_student():
# 获取当前线程关联的student
std = local_school.student
print("Hello, %s (in %s)" % (std, threading.current_thread().name)) def process_thread(name):
# 绑定 ThreadLocal 的 student
local_school.student = name
process_student() t1 = threading.Thread(target=process_thread, args=("zhangsan",), name="Thread-A")
t2 = threading.Thread(target=process_thread, args=("lisi",), name="Thread-B")
t1.start()
t2.start()
t1.join()
t2.join() # 输出:
# Hello, zhangsan (in Thread-A)
# Hello, lisi (in Thread-B)

10. 异步

# 示例:
from multiprocessing import Pool
import time
import os def test():
print("=== 进程池中的进程 === pid=%d, ppid=%d==" % (os.getpid(), os.getppid()))
for i in range(3):
print("=== %d ===" % i)
time.sleep(1)
return "hehe" def test2(args):
print("=== callback func == pid=%d" % os.getpid())
print("=== callback func == args=%s" % args) pool = Pool(3)
pool.apply_async(func=test, callback=test2) time.sleep(5) print("=== 主进程 = pid=%d ===" % os.getpid())

11. Join 和 Daemon

  • join:

    • join完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程才终止;
  • setDaemon(True):
    • 将线程声明为守护进程,必须在start()方法调用之前设置,这个方法基本和join是相反的;
    • 当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程就兵分两路,分别运行,那么当

      主线程完成想退出时,会检验子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。
    • 但是,有时候我们需要的是只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时,就可以使用setDaemon

      方法;
# 示例:
import threading
from time import ctime, sleep
import time def music(func):
for i in range(2):
print('Begin listening to %s. %s' % (func, ctime()))
sleep(2)
print('end listening %s' % ctime()) def movie(func):
for i in range(2):
print('Begin watching at the %s! %s' % (func, ctime()))
sleep(3)
print('end watching %s'% ctime()) threads = []
t1 = threading.Thread(target = music, args = ('七里香',))
threads.append(t1)
t2 = threading.Thread(target = movie, args = ('阿甘正传',))
threads.append(t2) if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start() print(threading.current_thread()) # 打印当前线程名称
print(threading.active_count()) #
print('all over %s', % ctime)

12. 线程中的队列(Queue)

  • queue定义了三种信息队列模式类:

    • Queue([maxsize]):FIFO队列模式,[maxsize]定义队列容量; 缺省,即无穷大;
    • LifoQueue([maxsize]):LIFO队列模式;
    • PriorityQueue([maxsize]):优先级队列模式,使用此队列时,项目应该是(priority,data)的形式;
# 示例一:
import queue
q = queue.Queue(maxsize = 10) # 存入一个值
q.put(item, block=True, timeout=None)
# block 为可选参数,如果队列满了的话,put(item),调用者将被阻塞, 而put(item,0)会报Full异常; # 取出一个值
q.get(item, block=False, timeout=None)
# block 为可选参数,如果队列为空, get(item,0)会报Empty异常; # 常用方法:
# q.qsize(): 返回队列大小;
# q.full(): 如果队列满了,返回True,否则返回False;
# q.empty(): 如果队列为空,返回True,否则返回False; # 示例二:
import threading
import queue
from time import sleep
from random import randint
class Production(threading.Thread):
def run(self):
while True:
r = randint(0, 100)
q.put(r)
print('生产出来%s号包子' % r)
sleep(1)
class Process(threading.Thread):
def run(self):
while True:
re = q.get()
print('吃掉%s号包子' % re) if __name__ == '__main__':
q = queue.Queue(10)
threads = [Production(), Production(), Production(), Process()]
for t in threads:
t.start()

参考资料:

Python 线程(threading)的更多相关文章

  1. Python 线程(threading) 进程(multiprocessing)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  2. python线程threading.Timer源码解读

    threading.Timer的作用 官方给的定义是: """Call a function after a specified number of seconds: t ...

  3. python线程threading

    线程示例: import threading import time # 唱歌任务 def sing(): # 扩展: 获取当前线程 # print("sing当前执行的线程为:" ...

  4. python中threading的用法

    摘自:http://blog.chinaunix.net/uid-27571599-id-3484048.html 以及:http://blog.chinaunix.net/uid-11131943- ...

  5. [python] 线程简介

    参考:http://www.cnblogs.com/aylin/p/5601969.html 我是搬运工,特别感谢张岩林老师! python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件 ...

  6. python 线程、多线程

    复习进程知识: python:主进程,至少有一个主线程 启动一个新的子进程:Process,pool 给每一个进程设定一下执行的任务:传一个函数+函数的参数 如果是进程池:map函数:传入一个任务函数 ...

  7. python 线程 进程 协程 学习

    转载自大神博客:http://www.cnblogs.com/aylin/p/5601969.html 仅供学习使用···· python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和 ...

  8. python学习笔记——线程threading (一)

    1 线程threading 1.1 基本概述 也被称为轻量级的进程. 线程是计算机多任务编程的一种方式,可以使用计算机的多核资源. 线程死应用程序中工作的最小单元 1.2 线程特点 (1)进程的创建开 ...

  9. python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon)

    python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon) 前言 今天小编YOYO请xiaoming和xiaowang吃火锅,吃完火锅的时候会有以下三种场景: - ...

随机推荐

  1. 如何生成项目的chm文档

    如何生成项目的chm文档 2014-11-30 Generate .chm based documentation of your project using SandCastle  tool

  2. 解决eclipse启动tomcat报错:Could not load the Tomcat server configuration at \Servers\Tomcat v6.0 Server at localhost-config. The Servers project is closed.

    报错信息已经说的很清楚了:The Servers project is closed.如图 打开即可: 另外,如果你修改了Servers project的name(比如说把这里的Servers改成了X ...

  3. dropload.js下拉加载更多

    项目中有用到下拉加载更多的地方,去网上找了一个插件,地址:http://ons.me/526.html总体还是不错的,可能自己不是特别了解这个插件,做项目时,也是遇到了无数问题.项目中要用的是两个ta ...

  4. linux中mysql安装的问题

    Starting MySQL.Manager of pid-file quit without updating file.[FAILED] 已解决 这是由于系统中/etc/my.cnf文件本身存在或 ...

  5. linux和windows动态库加载路径区别

    # linux和windows动态库加载路径区别 ### 简介------------------------------ linux加载动态库的路径是系统目录/lib和/usr/lib.- wind ...

  6. Mybatis Batch 批量操作

    Mybatis Batch 批量操作 http://www.blogjava.net/diggbag/articles/mybatis.html

  7. 微信小程序 - dialog

    实现了 标题,内容和按钮设置,可动态设置按钮,以及按钮点击事件的回调 可作为component 使用 直接上代码 //遮罩的代码 <viewclass="uiComponent uiC ...

  8. golang :连接数据库闲置断线的问题

    golang在进行数据库操作,一般来说我们使用Open函数创建一个数据库(操作)句柄:func Open(driverName, dataSourceName string) (*DB, error) ...

  9. iScroll框架解析——Android 设备页面内 div(容器,非页面)overflow:scroll; 失效解决(转)

    移动平台的活,兼容问题超多,今儿又遇到一个.客户要求在弹出层容器内显示内容,但内容条数过多,容器显示滚动条.按说是So easy,容器设死宽.高,CSS加属性 overflow:scroll; -we ...

  10. Think Python: How to Think Like a Computer Scientist

    Think Python: How to Think Like a Computer Scientist:http://greenteapress.com/thinkpython/html/index ...