一、概念
操作系统最小的调度单位,是一串指令的集合;
以一个整体的形式暴露给操作系统管理,里面包含对各种资源的调用,内存的管理,网络接口的调用等,对各种资源管理的集合就可以称为进程,例如:qq就是一个进程; 要操作cpu,必须要先创建一个线程; 所有在同一个进程里的线程是共享同一块内存空间的;
线程共享内存空间,进程的内存是独立的; 同一个进程的线程之间可以直接交流,两个进程想通信,必须通过一个中间代理来实现; 创建线程很简单,创建新进程需要对其父进程进行一次克隆; 一个线程可以控制和操作同一个进程里其他线程,但是进程只能操作子进程;
二、多线程小知识点
1、多线程基本实现
import threading
import time
def run ( name) :
print ( "task " , name)
time. sleep( 5 )
if __name__ == '__main__' :
t1 = threading. Thread( target= run, args= ( "t1" , ) )
t2 = threading. Thread( target= run, args= ( "t2" , ) )
t1. start( )
t2. start( )
import threading
import time
class MyThread ( threading. Thread) :
def __init__ ( self, name) :
super ( ) . __init__( )
self. name = name
def run ( self) :
print ( "task " , self. name)
time. sleep( 5 )
if __name__ == '__main__' :
t1 = MyThread( "t1" )
t2 = MyThread( "t2" )
t1. start( )
t2. start( )
2、等待线程停止: t.join()
import threading
import time
class MyThread ( threading. Thread) :
def __init__ ( self, name) :
super ( ) . __init__( )
self. name = name
def run ( self) :
print ( "task " , self. name)
time. sleep( 5 )
if __name__ == '__main__' :
start_time = time. time( )
threads_list = [ ]
for i in range ( 50 ) :
t = MyThread( i)
t. start( )
threads_list. append( t)
for t in threads_list:
t. join( )
end_time = time. time( )
cost_time = end_time - start_time
print ( "多线程运行, 共计耗时: %s秒" % cost_time)
3、守护线程:setDaemon,主线程结束时,守护线程都会强制结束
import threading
import time
class MyThread ( threading. Thread) :
def __init__ ( self, name) :
super ( ) . __init__( )
self. name = name
def run ( self) :
print ( "task " , self. name)
time. sleep( 5 )
if __name__ == '__main__' :
start_time = time. time( )
for i in range ( 50 ) :
t = MyThread( i)
t. setDaemon( True )
t. start( )
end_time = time. time( )
cost_time = end_time - start_time
print ( "多线程运行, 共计耗时: %s秒" % cost_time)
4、CPython GIL介绍:全局解释锁
注意点: 机智的同学可能会问到这个问题,就是既然你之前说过了,Python已经有一个GIL来保证同一时间只能有一个线程来执行了,为什么这里还需要lock? 注意啦,这里的lock是用户级的lock,跟那个GIL没关系 ,具体我们通过下图来看一下+配合我现场讲给大家,就明白了。
5、线程锁(互斥锁Mutex):threading.Lock()
import time
import threading
def addNum ( ) :
global num
print ( '--get num:' , num )
time. sleep( 1 )
lock. acquire( )
num -= 1
lock. release( )
num = 100
thread_list = [ ]
lock = threading. Lock( )
for i in range ( 100 ) :
t = threading. Thread( target= addNum)
t. start( )
thread_list. append( t)
for t in thread_list:
t. join( )
print ( 'final num:' , num )
6、python中lock和rlock(递归锁)的区别
在threading模块中,定义两种类型的琐:threading.Lock和threading.RLock。它们之间有一点细微的区别,通过比较下面两段代码来说明。 这两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。
import threading
lock = threading. Lock( )
lock. acquire( )
lock. acquire( )
lock. release( )
lock. release( )
import threading
rLock = threading. RLock( )
rLock. acquire( )
rLock. acquire( )
rLock. release( )
rLock. release( )
7、Semaphore(信号量)
互斥锁 同时只允许一个线程更改数据,而Semaphore 是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
import threading, time
def run ( n) :
semaphore. acquire( )
time. sleep( 1 )
print ( "run the thread: %s\n" % n)
semaphore. release( )
if __name__ == '__main__' :
num= 0
semaphore = threading. BoundedSemaphore( 5 )
for i in range ( 20 ) :
t = threading. Thread( target= run, args= ( i, ) )
t. start( )
while threading. active_count( ) != 1 :
pass
else :
print ( '----all threads done---' )
print ( num)
2.
总结