操作 python -- 进程与线程 (二)

  GIL锁

       Python虚拟机使用一个全局解释器锁(Global Interpreter Lock)来互斥线程对Python虚拟机的使用。为了支持多线程机制,一个基本的要求就是需要实现不同线程对共享资源访问的互斥,所以引入了GIL。
GIL:在一个线程拥有了解释器的访问权之后,其他的所有线程都必须等待它释放解释器的访问权,即使这些线程的下一条指令并不会互相影响。
在调用任何Python C API之前,要先获得GIL
GIL缺点:多处理器退化为单处理器;优点:避免大量的加锁解锁操作。

        无论你启多少个线程,你有多少个cpu, Python在执行一个进程的时候会淡定的在同一时刻只允许一个线程运行。所以,python是无法利用多核CPU实现多线程的。
       这样,python对于计算密集型的任务开多线程的效率甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

======================================================================

 类的继承方式创建线程对象

# import threading,time
# class MyThread(threading.Thread):
#     def __init__(self):
#         super().__init__()
#     def run(self):
#         print('ok')
#         time.sleep(2)
#         print('t1 out')
#
# t1=MyThread()
# t1.start()
# print('ending')

同步锁:锁通常被用来实现对共享资源的同步访问。为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放),待资源访问完后,再调用release方法释放锁。

# import threading,time
# lock=threading.Lock()#实例化一个锁对象
# num=100
# def sub():
#     global num
#     lock.acquire()#获得一个锁
#     timp=num
#     time.sleep(0.1)
#     num=timp-1
#     lock.release()#释放一个锁
#     time.sleep(2)
# l=[]
# for i in range(100):
#     t=threading.Thread(target=sub,args=())
#     t.start()
#     l.append(t)
# for t in l:
#     t.join()
#
#
# print(num)

'''
1、为什么有了GIL,还需要线程同步?

多线程环境下必须存在资源的竞争,那么如何才能保证同一时刻只有一个线程对共享资源进行存取?

加锁, 对, 加锁可以保证存取操作的唯一性, 从而保证同一时刻只有一个线程对共享数据存取.

通常加锁也有2种不同的粒度的锁:

    coarse-grained(粗粒度): python解释器层面维护着一个全局的锁机制,用来保证线程安全。
                            内核级通过GIL实现的互斥保护了内核的共享资源。

    fine-grained(细粒度):   那么程序员需要自行地加,解锁来保证线程安全,
                            用户级通过自行加锁保护的用户程序的共享资源。

 2、GIL为什么限定在一个进程上?
 
 你写一个py程序,运行起来本身就是一个进程,这个进程是有解释器来翻译的,所以GIL限定在当前进程;
 如果又创建了一个子进程,那么两个进程是完全独立的,这个字进程也是有python解释器来运行的,所以
 这个子进程上也是受GIL影响的                


'''

可重入锁:在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

import threading,time
# Rlock=threading.RLock()
# class MyThread(threading.Thread):
#     def __init__(self):
#         super().__init__()
#     def run(self):
#         self.foo()
#         self.bar()
#     def foo(self):
#         Rlock.acquire()
#         print('A {} {}'.format(self.name,time.ctime()))
#         Rlock.acquire()
#         print('B {} {}'.format(self.name,time.ctime()))
#         Rlock.release()
#         Rlock.release()
#     def bar(self):
#         Rlock.acquire()
#         print('C {} {}'.format(self.name, time.ctime()))
#         Rlock.acquire()
#         print('D {} {}'.format(self.name, time.ctime()))
#         Rlock.release()
#         Rlock.release()
# 
# for i in range(10):
#     t=MyThread()
#     t.start()

信号量

Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

应用:连接池

import threading,time

s=threading.Semaphore(5)#最大可同时接入5个线程

def func():
    if s.acquire():
        print(threading.currentThread().getName())#当前线程的名字
        time.sleep(1)
        s.release()

for i in range(20):
    t=threading.Thread(target=func,args=())
    t.start()



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值