threading和multiprocessing多线程与多进程学习笔记

Python的GIL锁

全局解释器锁

  • 全局解释器锁,是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行即便在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程。常见的GIL的解释器有CPython与Ruby MRI
import time
def start():
	i=0
	for i in range(10000000):
		i+=1
	return
def main():
	s=time.time()
	for i in range(10):
		start()
	print(time.time()-s)
main()
import threading
import time
def start():
	i=0
	for i in range(10000000):
		i+=1
	return

def main():
	ts={}
	s=time.time()
	for i in range(10):
		t=threading.Thread(target=start)
		t.start()
		ts[i]=t
		#t.join()
		#start()
	for i in range(10):
		ts[i].join()
	print(time.time()-s)

if __name__=='__main__':
	main()
'''
#5.812853813171387单线程
#5.460023880004883多线程,并未快多少
线程并发不如单线程顺序执行快,
这是得不偿失的,造成这种情况的就是GIL
,这里是计算密集型,所以不适用
'''
  • 多线程并发计算密集型一个线程大多数时间在阻塞
  • 多线程在IO密集(输入、输出#爬虫大多时就是)的时候有不错的性能

多线程以及非守护线程

import threading
import time
def start():
	time.sleep(1)
	print(threading.current_thread().name)
	print(threading.current_thread().isAlive())
	print(threading.current_thread().ident)
print('start')
t=threading.Thread(target=start,name='my first thread')
t.start()
print('stop')
'''
start
stop
my first thread
True
9548
'''
import threading
import time
def start():
	time.sleep(1)
	print(threading.current_thread().name)
	print(threading.current_thread().is_alive())
	print(threading.current_thread().ident)
print('start')
t=threading.Thread(target=start,name='my first thread')
t.start()
t.join() #join会阻塞线程,直到线程运行完毕。
print('stop')
'''
start
my first thread
True
1028
stop
'''
  • 主线程会跳过创建的线程继续执行
  • 知道创建的线程运行完毕
  • 程序结束

多线程以及守护线程

import threading
import time
def start():
	time.sleep(1)
	print(threading.current_thread().name)
	print(threading.current_thread().is_alive())
	print(threading.current_thread().ident)
print('start')
t=threading.Thread(target=start,name='my first thread')
t.setDaemon(True)
t.start()
print('stop')
'''
start
stop
'''
#用setDaemon(True)设置守护线程,守护线程会伴随主线程一起结束
#,但是也受join阻塞线程约束

LOCK锁

'''
两个线程操作同一个数字,
最后得到的数字是混乱的
'''
import threading
number=0
def addNumber():
	global number
	for i in range(10000000):
		number+=1
def downNumber():
	global number
	for i in range(10000000):
		number-=1
print('start')
t=threading.Thread(target=addNumber)
t2=threading.Thread(target=downNumber)
t.start()
t2.start()
t.join()
t2.join()
print(number)
print('stop')
#因为没有LOCK锁,每次执行结果都不一样
  • 所以当我们多个线程争抢同一资源时需要使用LOCK锁
import threading
lock=threading.Lock()
number=0
def addNumber():
	global number
	for i in range(10000000):
		lock.acquire() #获取锁
		number+=1
		lock.release() #释放锁

def downNumber():
	global number
	for i in range(10000000):
		lock.acquire()
		number-=1
		lock.release()
print('start')
t=threading.Thread(target=addNumber)
t2=threading.Thread(target=downNumber)
t.start()
t2.start()
t.join()
t2.join()
print(number)
print('stop')

递归锁RLOCK

import threading
class Test:
	rlock=threading.RLock()
	def __init__(self):
		self.number=0
	
	def execute(self,n):
		with Test.rlock:
			self.number+=n

	def add(self):
		with Test.rlock:
			self.execute(1)
	
	def down(self):
		with Test.rlock:
			self.execute(-1)

def add(test):
	for i in range(10000000):
		test.add()
def down(test):
	for i in range(10000000):
		test.down()

if __name__=='__main__':
	t=Test()
	t1=threading.Thread(target=add,args=(t,))
	t2=threading.Thread(target=down,args=(t,))
	t1.start()
	t2.start()
	t1.join()
	t2.join()
	print(t.number)
'''
只有拿到锁的线程才能释放锁
同一线程可以多次拿到锁
'''

避免GIL

  • 用multiprocessing替代Thread
  • 多进程代替多线程
  • 它使用了多进程而不是多线程。每个进程有自己的独立GIL,因此也不会出现进程之间的GIL争抢。
  • 多进程的创建和销毁开销也会更大,成本高。
  • 进程间无法看到对方数据,需要使用栈或者队列进行获取,编程复杂度提升
import multiprocessing
import time

def start(i):
	time.sleep(1)
	print(i)
	print(multiprocessing.current_process().name)
	print(multiprocessing.current_process().pid)
	print(multiprocessing.current_process().is_alive())
if __name__=='__main__':
	print('start')
	p=multiprocessing.Process(target=start,args=(1,),name='pl')
	p.start()
	p.join()
	print('stop')
'''
start
1
pl
12928
True
stop
'''

进程通信

  • Python多进程之间默认是无法通信的,因为是并发执行的,所以需要借助其他数据结构。
from multiprocessing import Process,Queue

def write(q):
	print('Process to write:%s'%Process.pid)
	for i in range(10):
		print('Put %d to queue...'%i)
		q.put(i)

def read(q):
	print('Process to read:%s'%Process.pid)
	while True:
		value=q.get()
		print('Get %d from queue'%value)

if __name__=='__main__':
	#父进程创建Queue,并传给各个子进程:
	q=Queue()
	pw=Process(target=write,args=(q,))
	pr=Process(target=read,args=(q,))
	#启动子进程pw,写入:
	pw.start()
	#启动子进程pr,读取:
	pr.start()
	#等待pw结束:
	pw.join()

进程池

  • 多个任务
import multiprocessing

def function_square(data):
	result=data*data
	return result

if __name__=='__main__':
	inputs=list(range(100))
	pool=multiprocessing.Pool(processes=4)
	#map把任务交给进程池
	pool_outputs=pool.map(function_square,inputs)
	pool.close()
	pool.join()
	print('Pool:',pool_outputs)
  • 单个任务
import multiprocessing
def function_square(data):
	result=data*data
	return result

if __name__=='__main__':
	pool=multiprocessing.Pool(processes=4)
	#apply把任务交给进程池
	pool_outputs=pool.apply(function_square,args=(10,))
	pool.close()
	pool.join()
	print('Pool:',pool_outputs)

线程池

  • pip install threadpool
import time
import threadpool
#执行比较耗时的函数,需要开启多线程
def get_html(url):
	time.sleep(3)
	print(url)
#使用多线程执行telnet函数
urls=[i for i in range(10)]
pool=threadpool.ThreadPool(10)#建立线程池
#提交任务给线程池
requests=threadpool.makeRequests(get_html,urls)
#开始执行任务
for req in requests:
	pool.putRequest(req)
pool.wait()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值