python锁
一、全局解释器锁(GIL)
1、什么是全局解释器锁
在同一个进程中只要有一个线程获取了全局解释器(cpu)的使用权限,那么其他的线程就必须等待该线程的全局解释器(cpu)使用权消失后才能使用全局解释器(cpu),即时多个线程直接不会相互影响在同一个进程下也只有一个线程使用cpu,这样的机制称为全局解释器锁(GIL)。任何时刻仅有 一个线程 在执行,即便在 多核心处理器 上,使用 GIL 的解释器也只允许同一时间执行一个线程。
2、全局解释器锁的好处
1、避免了大量的加锁解锁的好处
2、使数据更加安全,解决多线程间的数据完整性和状态同步
3、全局解释器的缺点
多核处理器退化成单核处理器,只能并发不能并行。
二、原始锁(Lock)
三、重入锁(RLock)
Lock:原始锁,原始锁是一个在锁定时不属于特定线程的同步基元组件,它是能用的最低级的同步基元组件。
RLock:重入锁,若要锁定锁,线程调用其 acquire() 方法;一旦线程拥有了锁,方法将返回。若要解锁,线程调用 release() 方法。 acquire()/release() 对可以嵌套,重入锁必须由获取它的线程释放。一旦线程获得了重入锁,同一个线程再次获取它将不阻塞。
区别:
- 在同一线程内,对RLock进行多次acquire()操作,程序不会阻塞。
- Lock在锁定时不属于特定线程,也就是说,Lock可以在一个线程中上锁,在另一个线程中解锁。而对于RLock来说,只有当前线程才能释放本线程上的锁,即解铃还须系铃人。
1、join ()方法:主线程运行过程中,需要插入一个子线程,且子线程运行结束后,主线程才能继续运行或停止,此时用join()方法
2、setDaemon()方法:主线程运行过程中,需要插入一个子线程,且主线程执行结束了,就不管子线程是否完成, 一并和主线程退出。必须在start() 方法调用之前设置。
1、GIL的作用:多线程情况下必须存在资源的竞争,GIL是为了保证在解释器级别的线程唯一使用共享资源(cpu)。
2、同步锁的作用:为了保证解释器级别下的自己编写的程序唯一使用共享资源产生了同步锁。
import threading
total = 0
def add(lock):
global total
for i in range(1000000):
lock.acquire()
total += 1
lock.release()
def desc(lock):
global total
for i in range(1000000):
lock.acquire()
total -= 1
lock.release()
if __name__ == '__main__':
lock = threading.Lock()
thread1 = threading.Thread(target=add, args=(lock,))
thread2 = threading.Thread(target=desc, args=(lock,))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total)
四、信号量(semaphore)
五、线程池
线程池就是管理线程的池子,当有任务要处理时,不用频繁创建新线程,而是从池子拿个线程出来处理。当任务执行完,线程并不会被销毁,而是在等待下一个任务。因此可以节省资源,提高响应速度。
线程池线程数量
- CPU(计算) 密集型任务:
将线程数设置为N(CPU核心数)+1,比CPU核心数多出来的一个线程是为了防止线程偶发的 缺页中断,或者其它原因导致的任务暂停而带来的影响。 - IO密集型任务:
这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理I/O的时间段内不会占用CPU来处理,这时就可以将CPU交出给其它线程使用。因此在I/O密集型任务的应用 中,可以多配置一些线程,具体的计算方法是 2N。
主进程的工作步骤
- 打开熟知端口(端口号为21),使客户进程能够连接上。
- 等待客户进程发出连接请求。
- 启动从属进程来处理客户进程发来的请求。从属进程对客户进程的请求处理完毕后即终止,但从属进程在运行期间根据需要还可能创建其他一些子进程。
- 回到等待状态,继续接受其他客户进程发来的请求。主进程和从属进程的处理是并发地进行。