单线程

#常规写法

import threading
import time def sayhi(num): # 定义每个线程要运行的函数
print("running on number:%s" % num)
time.sleep() if __name__ == '__main__':
t1 = threading.Thread(target=sayhi, args=(,)) # 生成一个线程实例
t2 = threading.Thread(target=sayhi, args=(,)) # 生成另一个线程实例 t1.start() # 启动线程
t2.start() # 启动另一个线程 print(t1.getName()) # 获取线程名
print(t2.getName()) 自定义线程类
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() if __name__ == '__main__':
t1 = MyThread()
t2 = MyThread() t1.start()
t2.start()

多线程

import threading
import time def sayhi(num): # 定义每个线程要运行的函数
print("running on number:%s" % num)
time.sleep() start_time=time.time()
if __name__ == '__main__':
for i in range(): ###多线程
t = threading.Thread(target=sayhi, args=(i,)) # 生成一个线程实例
t.start()
print (start_time-time.time()) ####打印时间 此时打印结果时间为0.0000几秒,是因为程序在执行完多线程时继续往下执行,而不会等待线程执行完在打印时间,所以打印出来的时间并不是多线程执行的时间 join()
线程执行后,主线程会等待所有线程执行完毕后继续往下走,下面实例介绍计算多线程执行时间 import threading
import time def sayhi(num): # 定义每个线程要运行的函数 print("running on number:%s" % num)
time.sleep() start_time=time.time() threads = [] ####定义一个列表,将所有的线程加进去
if __name__ == '__main__':
for i in range(): ###多线程
t = threading.Thread(target=sayhi, args=(i,)) # 生成一个线程实例
t.start()
threads.append(t) ####将每个线程添加到列表
for t in threads: ###循环整个列表,进行join(每个线程join完成后主线程才会继续往下走)
t.join() ###等待所有线程执行结束,相当于单线程 print (start_time-time.time())

示例二

#!/usr/bin/env python
#-*-coding:utf--*- import threading
from time import ctime,sleep
import time def music(func):
for i in range():
print ("Begin listening to %s. %s" %(func,ctime()))
sleep()
print("end listening %s"%ctime()) def move(func):
for i in range():
print ("Begin watching at the %s! %s" %(func,ctime()))
sleep()
print('end watching %s'%ctime()) threads = []
t1 = threading.Thread(target=music,args=('music',))
threads.append(t1)
t2 = threading.Thread(target=move,args=('movie',))
threads.append(t2) if __name__ == '__main__': for t in threads:
t.start()
print ("all over %s" %ctime())

守护线程

主线程不会等待守护线程结束在退出,会等待非守护线程执行完毕才退出

将线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,线程也会退出,由守护线程动的其它子线程会同时退出,不管是否执行完任务

线程锁

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 即同一时刻允许一个线程执行操作

###没有加锁时

import threading
import time,sys def addNum():
global num # 在每个线程中都获取这个全局变量
print('--get num:', num)
time.sleep()
num -= # 对此公共变量进行-1操作 num = # 设定一个共享变量
thread_list = [] for i in range():
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list: # 等待所有线程执行完毕 t.join()
print('final num:', num) 说明:
正常来讲,这个num结果应该是0, 但在python 2.7上多运行几次,会发现,最后打印出来的num结果不总是0,为什么每次运行的结果不一样呢?
假设你有A,B两个线程,此时都 要对num 进行减1操作, 由于2个线程是并发同时运行的,所以2个线程很有可能同时拿走了num=100这个初始变量交给cpu去运算,当A线程去处完的结果是99,但此时B线程运算完的结果也是99,两个线程同时CPU运算的结果再赋值给num变量后,结果就都是99。那怎么办呢? 很简单,每个线程在要修改公共数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。 加锁版本: import threading
import time gl_num =
lock = threading.RLock() ## 生成全局锁 def Func():
lock.acquire() #修改数据前加锁
global gl_num
gl_num +=
time.sleep()
print(gl_num)
lock.release() ###修改后释放 for i in range():
t = threading.Thread(target=Func)
t.start()

递归锁(即大锁之下在加小锁)

import threading, time

def run1():
print("grab the first part data")
lock.acquire()
global num
num += 1
lock.release() return num def run2():
print("grab the second part data")
lock.acquire()
global num2
num2 += 1
lock.release() return num2 def run3():
lock.acquire()
res = run1()
print('--------between run1 and run2-----')
res2 = run2()
lock.release()
print(res, res2) if __name__ == '__main__':
num, num2 = 0, 0
lock = threading.RLock() for i in range(10):
t = threading.Thread(target=run3)
t.start() while threading.active_count() != 1:
print(threading.active_count()) else: print('----all threads done---')
print(num, num2)

条件变量同步(condition)

有一类线程需要满足条件之后才能够继续执行,Python提供了threading.Condition 对象用于条件变量线程的支持,它除了能提供RLock()或Lock()的方法外,还提供了 wait()、notify()、notifyAll()方法。

lock_con=threading.Condition([Lock/Rlock]): 锁是可选选项,不传人锁,对象自动创建一个RLock()。
wait():条件不满足时调用,线程会释放锁并进入等待阻塞;
notify():条件创造后调用,通知等待池激活一个线程;
notifyAll():条件创造后调用,通知等待池激活所有线程。

示例

import threading,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 Consumer(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(Consumer())
for t in threads:
t.start()
for t in threads:
t.join()

信号量

互斥锁,同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如两个水龙头,那最多只允许2个人同时使用,后面的人只能等有人用完后才能使用。

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

计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)

BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。

实例:

import threading, time

def run(n):
semaphore.acquire()  
time.sleep(1)
print("run the thread: %s" % n)
semaphore.release() if __name__ == '__main__':
num = 0
semaphore = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行,有一个执行完毕后会执行另一个
for i in range(20):
t = threading.Thread(target=run, args=(i,))
t.start()

python 线程/线程锁/信号量的更多相关文章

  1. Python 线程同步锁, 信号量

    同步锁 import time, threading def addNum(): global num num -= 1 num = 100 thread_list = [] for i in ran ...

  2. python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式

    (1)锁:进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 虽然使用加锁的形式实现了 ...

  3. {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器

    Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...

  4. Python的并发并行[1] -> 线程[2] -> 锁与信号量

    锁与信号量 目录 添加线程锁 锁的本质 互斥锁与可重入锁 死锁的产生 锁的上下文管理 信号量与有界信号量 1 添加线程锁 由于多线程对资源的抢占顺序不同,可能会产生冲突,通过添加线程锁来对共有资源进行 ...

  5. Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量

    在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...

  6. Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量

    Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程:    1.线程是一堆指令,是操作系统调度 ...

  7. python 之 并发编程(守护线程与守护进程的区别、线程互斥锁、死锁现象与递归锁、信号量、GIL全局解释器锁)

    9.94 守护线程与守护进程的区别 1.对主进程来说,运行完毕指的是主进程代码运行完毕2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕​详细解释:1.主 ...

  8. Python并发编程-进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  9. 并发编程---线程 ;python中各种锁

    一,概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 --车间负责把资源整合到 ...

  10. 线程锁&信号量&gil

    线程锁 线程锁的主要目的是防止多个线程之间出现同时抢同一个数据,这会造成数据的流失.线程锁的作用类似于进程锁,都是为了数据的安全性 下面,我将用代码来体现进程锁的作用: from threading ...

随机推荐

  1. ServiceStack.Redis连接阿里云redis服务时使用连接池出现的问题

    创建连接池 private static PooledRedisClientManager prcm = CreateManager(new string[] { "password@ip: ...

  2. man -f/-k [keyword]在fedora 29 中报错nothing appropriate

    我们在使用 man 手册的时候,可以使用man -f [keyword]去查询keyword的在线文档,但是这时候会报错:(图来源自网络) 这是因为我们还没有建立 man 手册的索引缓存: 我们可以使 ...

  3. 如何让EasyUI的Tree或者ComboTree节点不显示图标?

    版本:jQuery EasyUI 1.3.2 通过测试,只需把节点的state属性设置为null即可使EasyUI的Tree或者ComboTree控件的节点不显示图标.

  4. SQLServer之删除约束

    使用SSMS数据库管理工具删除约束 1.连接数据库,选择数据表->展开键或者约束->选择要删除的约束->右键点击->选择删除. 2.在删除对象弹出框中->点击确定. 3. ...

  5. Scheme来实现八皇后问题(1)

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/9768105.html 作者:窗户 Q ...

  6. TCP/IP及内核参数优化调优

    Linux下TCP/IP及内核参数优化有多种方式,参数配置得当可以大大提高系统的性能,也可以根据特定场景进行专门的优化,如TIME_WAIT过高,DDOS攻击等等.如下配置是写在sysctl.conf ...

  7. Angular5 路由守卫

    今年下半年一直很忙,没有多少时间来写博客,很多笔记都记在了本地一起提交到了git上边. 夏末的时候做的两个vue项目中有接触到vue的路由守卫,今天在另外一个angular上,发现路由守卫有异常,导致 ...

  8. 大数据处理框架之Strom:Flume+Kafka+Storm整合

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 storm-0.9 apache-flume-1.6.0 ...

  9. tomcat目录

    1.解决Nginx+Tomcat下客户端https请求跳转成http的问题 2.tomcat配置通过域名直接访问项目首页步骤 3.tomcat配置文件server.xml详解 4.nginx-t/co ...

  10. spring启动component-scan类扫描加载过程(转)

    文章转自 http://www.it165.net/pro/html/201406/15205.html 有朋友最近问到了 spring 加载类的过程,尤其是基于 annotation 注解的加载过程 ...