• python多线程


    多线程

    • 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
    • 线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间

    线程的优点

    1. 多线程共享一个进程的地址空间
    2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
    3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
    4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)

    如何开启线程

    • threading模块(使用方法与multiprose一样)
    import time
    import random
    from threading import Thread
    
    def run(name):
    	print('%s is running'%name)
    	time.sleep(random.randrange(1,5))
    	print('%s is end'%name)
    
    if __name__ == '__main__':
    	t1 = Thread(target=run,args=('喵',))
    	t1.start()
    	print('主线程')
    
    import time
    from threading import Thread
    class MyThread(Thread):
    	def __init__(self,name):
    		super().__init__()
    		self.name = name
    
    	def run(self):
    		print('%s is running'%self.name)
    		time.sleep(2)
    		print('%s is end'%self.name)
    
    if __name__ == '__main__':
    	t1 = MyThread('喵')
    	t1.start()
    	print('主线程')
    
    thread对象的其他属性与方法
    from threading import Thread,currentThread,active_count,enumerate
    
    import time
    
    def task():
    	print('%s is running'%currentThread().getName())
    	time.sleep(2)
    	print('%s is done'%currentThread().getName())
    
    if __name__ == '__main__':
    	t = Thread(target=task,name='子线程')
    	t.start()
    	#t.setName('儿子进程1')  设置线程名字
    	print(t.isAlive())#判断线程是否存活
    	print('主线程',currentThread().getName())
    	# t.join()#等当前线程结束才继续执行主线程
    	print(active_count())	#活跃的线程数
    	print(enumerate())#[<_MainThread(MainThread, started 140735697388416)>, <Thread(子线程, started 123145519529984)>]
    

    守护线程

    • 在一个进程内,只有一个线程,线程运行结束,代表这个一个进程结束。
    • 在一个进程内,开多个线程,主线程在代码运行完毕,还需要等待其他线程干完活才会结束

    互斥锁

    • 将并行编程串行,牺牲效率保证数据安全,与进程的互斥锁一样使用

    GIL全局解释器锁

    pass

    死锁与递归锁

    • 互斥锁只能acquire一次
    from threading import Thread,Lock
    import time
    mutexA = Lock()
    mutexB = Lock()
    
    class MyThread(Thread):
    	def run(self):
    		self.f1()
    		self.f2()
    
    	def f1(self):
    		mutexA.acquire()
    		print('%s 拿到了A锁'%self.name)
    		mutexB.acquire()
    		print('%s 拿到了B锁'%self.name)
    		mutexB.release()
    		mutexA.release()
    
    	def f2(self):
    		mutexB.acquire()
    		print('%s 拿到了B锁' % self.name)
    		time.sleep(0.1)
    		mutexA.acquire()
    		print('%s 拿到了A锁' % self.name)
    		mutexA.release()
    		mutexB.release()
    
    for i in range(10):
    	t = MyThread()
    	t.start()
    
    
    • 递归锁:可以acquire多次,每次acquire一次计数器+1,只要计数为0,才能被其他线程抢到
    # 递归锁
    from threading import Thread,RLock
    import time
    mutexA = mutexB = RLock()
    
    class MyThread(Thread):
    	def run(self):
    		self.f1()
    		self.f2()
    
    	def f1(self):
    		mutexA.acquire()
    		print('%s 拿到了A锁'%self.name)
    		mutexB.acquire()
    		print('%s 拿到了B锁'%self.name)
    		mutexB.release()
    		mutexA.release()
    
    	def f2(self):
    		mutexB.acquire()
    		print('%s 拿到了B锁' % self.name)
    		time.sleep(0.1)
    		mutexA.acquire()
    		print('%s 拿到了A锁' % self.name)
    		mutexA.release()
    		mutexB.release()
    
    for i in range(10):
    	t = MyThread()
    	t.start()
    

    信号量:可以同时运行多个线程

    from threading import Thread,Semaphore,currentThread
    import time,random
    
    sm = Semaphore(3)
    def task():
    	with sm:
    		print('%s is run'%currentThread().getName())
    		time.sleep(random.randint(1,3))
    
    if __name__ == '__main__':
    	for i in range(10):
    		t = Thread(target=task)
    		t.start()
    

    Event事件:实现线程同步

    1. event.wait()#等待(可设置等待时间)
    2. event.set()#开始
    3. event.is_set()
    from threading import Thread,Event
    import time
    event = Event()
    def student(name):
    	print('学生 %s正在听课'%name)
    	event.wait()
    	print('学生%s下课了'%name)
    
    def teacher(name):
    	print('老师%s 正在上课'%name)
    	time.sleep(7)
    	print('老师%s 让学生下课了'%name)
    	event.set()
    
    if __name__ == '__main__':
    	s1 = Thread(target=student,args=('wualin',))
    	s2 = Thread(target=student,args=('wxx',))
    	s3 = Thread(target=student,args=('zxx',))
    	t1 = Thread(target=teacher,args=('egon',))
    	s1.start()
    	s2.start()
    	s3.start()
    	t1.start()
    

    定时器

    线程queue

    • 先进先出
    import queue
    q = queue.Queue(3) #先进先出->队列
    q.put(5)
    q.put('miao')
    q.put('sta')
    
    print(q.get())
    print(q.get())
    print(q.get())
    
    #get 和 put可设置是否阻塞以及阻塞时间
    
    print(q.get(block=True,timeout=3))
    
    • 后进先出
    q = queue.LifoQueue(3)#后进先出->堆栈
    
    q.put('fisrt')
    q.put(2)
    q.put('miao')
    
    print(q.get())
    print(q.get())
    print(q.get())
    
    • 优先级队列
    import queue
    q = queue.PriorityQueue(3)#优先级队列
    q.put((10,'one'))
    q.put((40,'two'))
    q.put((20,'three'))
    #数字越小优先级越高
    print(q.get())
    print(q.get())
    print(q.get())
    

    进程池与线程池

    • 池对线程或进程数量进行一个限制
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    import os,time,random
    
    def task(name):
    	print('name:%s pid:%s run'%(name,os.getpid()))
    	time.sleep(random.randint(1,3))
    
    
    if __name__ == '__main__':
    	pool = ProcessPoolExecutor(4)#进程池
    	for i in range(10):
    		pool.submit(task,'egon%s'%i)#异步调用
    
    	pool.shutdown()#把往进程池提交任务的入口关闭
    
    	print('主')
    

    异步调用与回调机制

    • 提交任务的两种方式
      • 同步调用:提交完任务后,就在原地等待任务执行完毕,拿到结果再执行下一行代码,程序是串行执行

      • 异步调用

        from concurrent.futures import ThreadPoolExecutor
    import time,random
    
    def eat(name):
    	print('%s is eating'%name)
    	time.sleep(random.randint(2,5))
    	res = random.randint(5,10)*'#'
    	return {'name':name,'size':res}
    
    def count(weith):
    	weith = weith.result()#
    	name = weith['name']
    	size = len(weith['size'])
    	print('name:%s eat is %s'%(name,size))
    
    if __name__ == '__main__':
    	pool = ThreadPoolExecutor(5)
    	pool.submit(eat,'miao').add_done_callback(count)#回调机制
    	pool.submit(eat,'car').add_done_callback(count)
    	pool.submit(eat,'dog').add_done_callback(count)
    	pool.submit(eat,'zhang').add_done_callback(count)
    
  • 相关阅读:
    ef 模块实体 转json出错的解决
    两个简单的前台显示构架01
    oracle 常用系统表
    直接在文本看代码,谁能指出错在哪里
    action script3.0殿堂之路.pdf 读书笔记
    flashbuilder4.6 as3.0 调试服务器端swf(flash)文件
    .ashx 一般处理文件阻塞处理,所有页面卡死的解决方案
    计算一年中所有周的时间段
    整理的靠谱的软件试玩平台,已亲测能提现
    Java限制同一字符出现N次
  • 原文地址:https://www.cnblogs.com/wualin/p/9956909.html
Copyright © 2020-2023  润新知