• 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. 转:Linux下which、whereis、locate、find 命令的区别

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索.这些是从网上找到的资料,因为有时很长时间不会用到,当要用的时候经常弄混了,所以放到这里方便使用. which    ...

  2. strerror和perror函数详解

    /*#include <string.h> char *strerror(int errnum); 它返回errnum的值所对应的错误提示信息,例如errnum等于12的话,它就会返回&q ...

  3. saveFileDialog对话框

    private void button1_Click(object sender, EventArgs e) { saveFileDialog1.Filter = "*.txt|*.txt| ...

  4. Spider Studio 新版本 (20140225) - 设置菜单调整 / 提供JQueryContext布局相关的方法

    这是年后的第一个新版本, 包含如下: 1. 先前去掉的浏览器设置功能又回来了! 说来惭愧, 去掉了这两个功能之后发现浏览经常会被JS错误打断, 很不方便, 于是乎又把它们给找回来了. :) 2. 为J ...

  5. js函数与 Promise的使用

    JavaScript的函数不但是“头等公民”,而且可以像变量一样使用,具有非常强大的抽象能力. 定义函数的方式如下: function abs(x) { if (x >= 0) { return ...

  6. 模板题 + KMP + 求最小循环节 --- HDU 3746 Cyclic Nacklace

    Cyclic Nacklace Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=3746 Mean: 给你一个字符串,让你在后面加尽 ...

  7. doAfterBody()方法是在( )接口中定义的。

    A.Tag B.IterationTag C.BodyTag D.TagSupport 解答:B

  8. VC++ 窗口拆分CSplitterWnd

    前言         当前许多优秀的软件都采用“多视”技术. 所谓“多视”,是指在同一个框架窗口里同时显示多个视图. 通过运用这种技术,可以在框架的有限控件内同时提供用户更大的信息量,并且使得用户界面 ...

  9. apacheserver全局配置具体解释

    server标识相关指令: ServerName ServerAdmin ServerSignature ServerTokens UseCanonicalName UseCanonicalPhysi ...

  10. Hadoop单机安装配置过程:

    1. 首先安装JDK,必须是sun公司的jdk,最好1.6版本以上. 最后java –version 查看成功与否. 注意配置/etc/profile文件,在其后面加上下面几句: export JAV ...