做网站渠道,东莞做网站公司有哪些,wordpress装多站点,建设网站的机构文章目录 一、线程、进程、协程区别二、创建线程1、函数创建2、类创建 三、线程锁1、Lock2、死锁2.1加锁之后处理业务逻辑#xff0c;在释放锁之前抛出异常#xff0c;这时的锁没有正常释放#xff0c;当前的线程因为异常终止了#xff0c;就会产生死锁。2.2开启两个或两个… 文章目录 一、线程、进程、协程区别二、创建线程1、函数创建2、类创建 三、线程锁1、Lock2、死锁2.1加锁之后处理业务逻辑在释放锁之前抛出异常这时的锁没有正常释放当前的线程因为异常终止了就会产生死锁。2.2开启两个或两个以上的线程不同的线程得到了不同的锁都在等待对方释放锁但是都在阻塞所以产生了死锁2.3在同一线程里多次取获得锁第一次获取锁后还未释放再次获得锁 3、RLock 四、线程通信1、condition2、semaphore 一、线程、进程、协程区别
1. 进程是资源分配的独立单位是应用程序的载体 进程之间是相互独立资源不共享一个进程由多个线程构成2.线程是资源分配的最小单位线程共享进程的资源3.协程是用户态执行的轻量级编程模型由单一线程内部发出控制信号进行调度协程允许不同入口点在不同的位置暂停或开始程序协程本质就是一个小线程多线程适合于 I/O 密集型任务如网络请求、文件读写等可以提高并发性和响应性。
多进程适用于 CPU 密集型任务如大量计算、图像处理等可以利用多核处理器加速运算。二、创建线程
在Python中创建线程主要依靠内置的threading模块。线程类Thread的常用方法如下表
序号方法含义1start()创建一个Thread子线程实例并执行该实例的run()方法2run()子线程需要执行的目标任务3join()主进程阻塞等待子线程直到子线程结束才继续执行可以设置等待超时时间timeout4is_alive()判断子线程是否终止5daemon()设置子线程是否随主进程退出而退出,默认是False
threading.current_thread()获取到当前线程。
获取线程后可以得到两个比较重要的属性name和ident分别是线程名称和id。
创建线程可以使用两种方法使用函数或类创建。
1、函数创建
import threading
import timedef myThread(i):start time.time()my_thread_name threading.current_thread().name # 当前线程的名字time.sleep(i)my_thread_id threading.current_thread().ident # 当前线程idprint(当前线程为{}线程ID{}所在进程为{}.format(my_thread_name, my_thread_id, os.getpid()))print(%s线程运行时间结束耗时%s... % (my_thread_name, time.time() - start))# 创建三个线程
def fun():t1 time.time()thread []for i in range(1, 4):t threading.Thread(targetmyThread,name线程%s % i, args(i,))t.start()thread.append(t)for i in thread:i.join() # 阻塞主线程if __name__ __main__:fun()threading.Thread(groupNone,targetNone,name,args,kwargs{}daemonFalse)
group:预留参数不需要传递
target:目标代码要执行的内容
name:线程名称字符串
args:是target的参数可迭代对象
kwargs是target的参数是一个字典
daemon设置线程为守护线程2、类创建
class myThread(threading.Thread):def __init__(self,nameNone):super().__init__()self.name namedef run(self):start time.time()my_thread_name threading.current_thread().name # 当前线程的名字time.sleep(3)my_thread_id threading.current_thread().ident # 当前线程idprint(当前线程为{}线程ID{}所在进程为{}.format(my_thread_name, my_thread_id, os.getpid()))print(%s线程运行时间结束耗时%s... % (my_thread_name, time.time() - start))# 创建三个线程
def fun():t1 time.time()thread []for i in range(1, 4):t myThread(name线程%s % i)t.start()thread.append(t)for i in thread:i.join() # 阻塞主线程直到子线程执行完毕再运行主线程if __name__ __main__:fun()三、线程锁
多线程一个很大的问题是数据不安全因为线程之间的数据是共享的。多线程可以通过线程锁来进行数据同步可用于保护共享资源同时被多个线程读写引起冲突导致错误
import threading
x 0
# lock threading.RLock()
def increment():global xname threading.current_thread().namefor _ in range(1000000):x 1print(name, x)
threads []
for _ in range(3):t threading.Thread(targetincrement)threads.append(t)t.start()
for t in threads:t.join()
print(Final value of x:, x)#Thread-2 1435674
#Thread-1 1423093
#Thread-3 1727936
#Final value of x: 1727936可以看出开启三个线程在0的基础上每次加1000000得到的结果应该是3000000.但不是这样的
1、Lock
线程同步能够保证多个线程安全访问竞争资源最简单的同步机制是引入互斥锁。互斥锁为资源设置一个状态锁定和非锁定。某个线程要更改共享数据时先将其锁定此时资源的状态为“锁定”其他线程不能更改直到该线程释放资源将资源的状态变成“非锁定”其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作从而保证了多线程情况下数据的正确性。
import threading
x 0
lock threading.Lock()
def increment():global xname threading.current_thread().namelock.acquire()try:for _ in range(1000000):x 1print(name, x)finally:lock.release()
threads []
for _ in range(3):t threading.Thread(targetincrement)threads.append(t)t.start()for t in threads:t.join()
print(Final value of x:, x)#Thread-1 1000000
#Thread-2 2000000
#Thread-3 3000000
#Final value of x: 3000000使用了锁之后代码运行速度明显降低这是因为线程由原来的并发执行变成了串行不过数据安全性得到保证。
还可以使用with lock这种上下文格式自动管理上锁和释放锁。
import threading
x 0
lock threading.Lock()
def increment():global xname threading.current_thread().namewith lock:for _ in range(1000000):x 1print(name, x)
threads []
for _ in range(3):t threading.Thread(targetincrement)threads.append(t)t.start()
for t in threads:t.join()
print(Final value of x:, x)#Thread-1 1000000
#Thread-2 2000000
#Thread-3 3000000
#Final value of x: 3000000一般来说加锁以后还要有一些功能实现在释放之前还有可能抛异常一旦抛出异常锁是无法释放但是当前线程可能因为这个异常被终止了这就产生了死锁。死锁解决办法
1、使用 try..except..finally 语句处理异常、保证锁的释放2、with 语句上下文管理锁对象支持上下文管理。只要实现了__enter__和__exit__魔术方法的对象都支持上下文管理。另一种是
锁的应用场景独占锁 锁适用于访问和修改同一个共享资源的时候即读写同一个资源的时候。共享锁 如果共享资源是不可变的值时所有线程每一次读取它都是同一样的值这样的情况就不需要锁。使用锁的注意事项少用锁必要时用锁。使用了锁多线程访问被锁的资源时就变成了串行要么排队执行要么争抢执行。
加锁时间越短越好不需要就立即释放锁。
一定要避免死锁。
不使用锁时有了效率但是结果是错的。使用了锁变成了串行效率地下但是结果是对的。2、死锁
2.1加锁之后处理业务逻辑在释放锁之前抛出异常这时的锁没有正常释放当前的线程因为异常终止了就会产生死锁。
解决方案
1、使用 try..except..finally 语句处理异常、保证锁的释放2、with 语句上下文管理锁对象支持上下文管理。只要实现了__enter__和__exit__魔术方法的对象都支持上下文管理。2.2开启两个或两个以上的线程不同的线程得到了不同的锁都在等待对方释放锁但是都在阻塞所以产生了死锁
解决方案
1、不同线程中获得锁的顺序一致不能乱2、使用递归锁RLock。2.3在同一线程里多次取获得锁第一次获取锁后还未释放再次获得锁
解决方案
1、使用递归锁RLock。3、RLock
递归锁也被称为“锁中锁”指一个线程可以多次申请同一把锁但是不会造成死锁这就可以用来解决上面的死锁问题。
import threading
x 0
lock threading.RLock()
def increment():global xname threading.current_thread().namelock.acquire()lock.acquire()try:for _ in range(1000000):x 1print(name, x)finally:lock.release()lock.release()
threads []
for _ in range(3):t threading.Thread(targetincrement)threads.append(t)t.start()
for t in threads:t.join()
print(Final value of x:, x)#Thread-1 1000000
#Thread-2 2000000
#Thread-3 3000000
#Final value of x: 3000000RLock内部维护着一个Lock和一个counter变量counter记录了acquire的次数从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release其他的线程才能获得资源。
四、线程通信
1、condition
Condition可以认为是一把比Lock和RLOK更加高级的锁其在内部维护一个琐对象默认是RLock可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法其含义与琐的acquire, release方法一致其实它只是简单的调用内部琐对象的对应的方法而已。
运行原理可以认为Condition对象维护了一个锁Lock/RLock)和一个waiting池。线程通过acquire获得Condition对象当调用wait方法时线程会释放Condition内部的锁并进入blocked状态同时在waiting池中记录这个线程。当调用notify方法时Condition对象会从waiting池中挑选一个线程通知其调用acquire方法尝试取到锁。Condition对象的构造函数可以接受一个Lock/RLock对象作为参数如果没有指定则Condition对象会在内部自行创建一个RLock。除了notify方法外Condition对象还提供了notifyAll方法可以通知waiting池中的所有线程尝试acquire内部锁。由于上述机制处于waiting状态的线程只能通过notify方法唤醒所以notifyAll的作用在于防止有的线程永远处于沉默状态。import threading
import time
from queue import Queueclass Producer(threading.Thread):# 生产者函数def run(self):global countwhile True:if con.acquire():# 当count 小于等于1000 的时候进行生产if count 1000:con.wait()else:count count 100msg self.name produce 100, count str(count)print(msg)# 完成生成后唤醒waiting状态的线程# 从waiting池中挑选一个线程通知其调用acquire方法尝试取到锁con.notify()con.release()time.sleep(1)class Consumer(threading.Thread):# 消费者函数def run(self):global countwhile True:# 当count 大于等于100的时候进行消费if con.acquire():if count 100:con.wait()else:count count - 5msg self.name consume 5, count str(count)print(msg)con.notify()# 完成生成后唤醒waiting状态的线程# 从waiting池中挑选一个线程通知其调用acquire方法尝试取到锁con.release()time.sleep(1)count 0
con threading.Condition()def test():for i in range(2):p Producer()p.start()for i in range(5):c Consumer()c.start()
if __name__ __main__:test()#Thread-1 produce 100, count100
#Thread-2 produce 100, count200
#Thread-3 consume 5, count195
#Thread-4 consume 5, count190
#Thread-5 consume 5, count185
#Thread-6 consume 5, count180
#Thread-7 consume 5, count175
#Thread-2 produce 100, count275
#Thread-3 consume 5, count2702、semaphore
semaphore是python中的一个内置的计数器内部使用了Condition对象多线程同时运行能提高程序的运行效率但是并非线程越多越好而 semaphore 信号量可以通过内置计数器来控制同时运行线程的数量启动线程(消耗信号量)内置计数器会自动减一线程结束(释放信号量)内置计数器会自动加一内置计数器为零启动线程会阻塞直到有本线程结束或者其他线程结束为止; 创建多个线程同一时间运行三个线程
import threading
# 导入时间模块
import time# 添加一个计数器最大并发线程数量5(最多同时运行5个线程)
semaphore threading.Semaphore(2)def foo():semaphore.acquire() #计数器获得锁time.sleep(2) #程序休眠2秒print(当前时间,time.ctime()) # 打印当前系统时间semaphore.release() #计数器释放锁if __name__ __main__:thread_list list()for i in range(6):tthreading.Thread(targetfoo,args()) #创建线程thread_list.append(t)t.start() #启动线程for t in thread_list:t.join()print(程序结束)#当前时间 Tue Jul 30 11:18:38 2024
#当前时间 Tue Jul 30 11:18:38 2024
#当前时间 Tue Jul 30 11:18:40 2024
#当前时间 Tue Jul 30 11:18:40 2024
#当前时间 Tue Jul 30 11:18:42 2024
#当前时间 Tue Jul 30 11:18:42 2024
#程序结束因为Semaphore使用了Condition线程之间仍然有锁保证线程数据安全