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)
posted @ 2018-11-14 11:12  Wualin  阅读(121)  评论(0)    收藏  举报