精华内容
下载资源
问答
  • 当一个进程中同时启动的线程,需要对同一个资源(比如变量)update需求时,使用同步,可以在同一时间保证只有一个进程占用资源,其他线程处于阻塞中。 3.递归 同时启动的线程,都需要用到资源A和...

    初学者笔记,非专业,或有出入。
    锁的分类:
    1.GIL(Global Interpreter Lock)全局解释器锁
    2.同步锁

    当一个进程中同时启动的几个线程,需要对同一个资源(比如变量)有update需求时,使用同步锁,可以在同一时间保证只有一个进程占用资源,其他线程处于阻塞中。

    3.递归锁

    使用场景:
    线程一:先使用A,过程中需要用到B,使用完B后,才能继续A的剩余工作;
    线程二:先使用B,过程中需要用到A,使用完A后,才能继续B的剩余工作。
    死锁发生:线程一get到A时,线程二get到B,而他们都需要对方的资源才能进一步释放自身get的资源,就造成了相互等待。
    

    解决办法:为了防止不同线程抢占不同资源,而又相互等待。可以将资源A和资源B上同样的一把锁(每个资源一把锁,只是锁长的一样,这两把锁可以看作是同一串上的两把锁),然后在线程中进行两次lock动作,这样就可以一次性锁住两个资源。因为是同一串上的,所以在acquire其中一个时,连带另一个也被线程占用,但是也需要一个acquire动作,才能真正lock住另外一个资源。

    4.Semaphore

    当有10个线程,每次最多只想要并行5个线程时,可以使用threading.Semaphore(5),来规定每次最多5个线程并行进行
    

    5.Condition

    浅显的理解是,当两个线程相互有条件要求时,比如库存清零时,消费者会等待,知道生产者生产出产品,而当有库存非零时,生产者等待,消费者消费。
    

    6.Event

    当线程A需要线程B来触发时,会用到Event。
    
    展开全文
  • python GIL

    2019-09-25 10:58:38
    Python的GIL锁  python的GIL锁是什么?  python内置的一个全局解释器锁,锁的作用就是保证同一时刻一个进程中只有一个县城可以被cpu调度.  为什么有着吧GIL锁?  python语言的创始人在开发这门...GIL锁有几种: ...

    Python的GIL锁

      python的GIL锁是什么?

        python内置的一个全局解释器锁,锁的作用就是保证同一时刻一个进程中只有一个县城可以被cpu调度.

      为什么有着吧GIL锁?

        python语言的创始人在开发这门语言时,目的是快速把语言开发出来,如果加上GIL锁(C语言加锁),切换时按照100条字符串指令来进行线程间的切换.

     

    GIL锁有几种:

      1,Lock(一次放一个)

        线程安全,多线程操作时,内部会让所有线程排队处理.

        如: list/dict/Queue

        非线程安全 + 人 =>排队处理

        

        需求:

          a,创建100个线程,在列表中追加8

          b,创建100个线程

            v=[]

            锁

            - 把自己添加到列表中.

            - 在读取列表的最后一个.

            解锁

         所以锁一个代码块推荐使用以下代码:

      

    import threading
    import time
    
    v = []
    lock = threading.Lock()
    
    def func(arg):
        lock.acquire()
        v.append(arg)
        time.sleep(0.01)
        m = v[-1]
        print(arg,m)
        lock.release()
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    Lock

     

      2,RLock(一次放一个)

     

    import threading
    import time
    
    v = []
    lock = threading.RLock()
    def func(arg):
        lock.acquire()
        lock.acquire()
    
        v.append(arg)
        time.sleep(0.01)
        m = v[-1]
        print(arg,m)
    
        lock.release()
        lock.release()
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    RLock

     

      3,BoundedSemaphore(一次放N个) 又称信号量

     

    import time
    import threading
    
    lock = threading.BoundedSemaphore(3)
    def func(arg):
        lock.acquire()
        print(arg)
        time.sleep(1)
        lock.release()
    
    
    for i in range(20):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    BoundedSemaphore

     

      4,Condition(一次放x个)

     有两种方式:

    方式,一

    import time
    import threading
    
    lock = threading.Condition()
    
    
    def func(arg):
        print('线程进来了')
        lock.acquire()
        lock.wait() # 加锁
    
        print(arg)
        time.sleep(1)
    
        lock.release()
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    while True:
        inp = int(input('>>>'))
    
        lock.acquire()
        lock.notify(inp)
        lock.release()
    View Code

     

    方式,二

    def xxxx():
    print('来执行函数了')
    input(">>>")
    # ct = threading.current_thread() # 获取当前线程
    # ct.getName()
    return True
    
    def func(arg):
    print('线程进来了')
    lock.wait_for(xxxx)
    print(arg)
    time.sleep(1)
    
    for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()
    View Code

     

      5,Event(一次放所有)

    import time
    import threading
    
    lock = threading.Event()
    
    
    def func(arg):
        print('线程来了')
        lock.wait() # 加锁:红灯
        print(arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    input(">>>>")
    lock.set() # 绿灯
    
    
    lock.clear() # 再次变红灯
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    input(">>>>")
    lock.set()
    Event

     下面简单介绍一下:

    threading.local

      作用:

        内部自动为每个线程维护一个空间(字典),用于当前存取属于自己的值.保证线程之间的数据隔离.

        {

        线程ID: {...}

        线程ID: {...}

        线程ID: {...}

        }

      示例:

    import time
    import threading
    
    v = threading.local()
    
    def func(arg):
        # 内部会为当前线程创建一个空间用于存储:phone=自己的值
        v.phone = arg
        time.sleep(2)
        print(v.phone,arg) # 去当前线程自己空间取值
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    threading.local

    那么原理是怎么回事呢?

      还是上代码:

    import time
    import threading
    INFO = {}
    class Local(object):
    
        def __getattr__(self, item):
            ident = threading.get_ident()
            return INFO[ident][item]
    
        def __setattr__(self, key, value):
            ident = threading.get_ident()
            if ident in INFO:
                INFO[ident][key] = value
            else:
                INFO[ident] = {key:value}
    
    obj = Local()
    
    def func(arg):
        obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1)
        time.sleep(2)
        print(obj.phone,arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    threading.local原理代码解析

      

     

    转载于:https://www.cnblogs.com/while-number/p/9627788.html

    展开全文
  • 解决线程同步的几种方法: Lock、RLock、Condition、Barrier、semaphore 1)Lock ,一旦线程获得,其它试图获取线程将被阻塞。 当用阻塞参数设置为 False 时, 不要阻止。如果将阻塞设置为 True 的...

     

     线程同步技术:

    解决多个线程争抢同一个资源的情况,线程协作工作。一份数据同一时刻只能有一个线程处理。

     

    解决线程同步的几种方法:

    Lock、RLock、Condition、Barrier、semaphore

     

    1)Lock 锁

    锁,一旦线程获得锁,其它试图获取锁的线程将被阻塞。

     当用阻塞参数设置为 False 时, 不要阻止。如果将阻塞设置为 True 的调用将阻止, 则立即返回 False;否则, 将锁定设置为锁定并返回 True。

     

    Lock的方法:
    acquire(blocking=True,timeout=-1)  加锁。默认True阻塞,阻塞可以设置超时时间。非阻塞时成功获取锁返回True,否则返回False。

    当blocking设置为False时,不阻塞,同一个锁对象,其它线程可以重用,但最后都必须释放。

    如果设置为True(默认True),其它试图调用锁的线程将阻塞,并立即返回False。阻塞可以设置超时时间。

     

    release() 释放锁。可以从任何线程调用释放。已上锁的锁,会被重置为unlocked,对未上锁的锁调用,会抛RuntimeError异常: cannot release un-acquired lock。

     

     

    不使用Lock的例子:

    #不使用Lock锁的例子
    import logging
    import threading,time
    logging.basicConfig(level=logging.INFO)
    
    # 10 -> 100cups
    cups = []
    lock = threading.Lock()
    
    
    def worker(lock:threading.Lock,task=100):
        while True:
            count = len(cups)
            time.sleep(0.1)
    
            if count >= task:
                break
    
            logging.info(count)
            cups.append(1)
            logging.info("{} make 1........ ".format(threading.current_thread().name))
        logging.info("{} ending=======".format(len(cups)))
    
    for x in range(10):
        threading.Thread(target=worker,args=(lock,100)).start()
    
    运行结果:
    INFO:root:Thread-7 make 1........ 
    INFO:root:93
    INFO:root:Thread-5 make 1........ 
    INFO:root:95
    INFO:root:Thread-6 make 1........ 
    INFO:root:92
    INFO:root:Thread-2 make 1........ 
    INFO:root:94
    INFO:root:Thread-8 make 1........ 
    INFO:root:97
    INFO:root:Thread-10 make 1........ 
    INFO:root:96
    INFO:root:Thread-4 make 1........ 
    INFO:root:98
    INFO:root:Thread-1 make 1........ 
    INFO:root:99
    INFO:root:Thread-9 make 1........ 
    INFO:root:109 ending=======
    INFO:root:109 ending=======
    INFO:root:109 ending=======
    

      还是使用前面的10个工人生产100杯子的例子, 当做到99个杯子时,10个工人都发现还少一个,都去做了一个,一共做了109个,超出了100个,就发生了不可预期的结果。

     

    临界线判断失误,多生产了杯子。

     

    解决方法就可以用锁,来解决资源争抢。当一个人看杯子数量时,就上锁,其它人只能等着,看完杯子后发现少一个就把这最后一个做出来,然后数量加一,解锁,其他人再看到已经有100个杯子时,就可以停止工作。

     

    加锁的时机非常重要:看杯子数量时加锁,增加数量后释放锁。

      

    使用Lock的例子:

    #Lock
    import logging
    import threading
    import time
    logging.basicConfig(level=logging.INFO)
    
    # 10 -> 100cups
    cups = []
    lock = threading.Lock()
    
    
    def worker(lock:threading.Lock,task=100):
        while True:
            if lock.acquire(False):
                count = len(cups)
    
                time.sleep(0.1)
                
                if count >= task:
                    lock.release()
                    break
                logging.info(count)
    
                cups.append(1)
                lock.release()
                logging.info("{} make 1........ ".format(threading.current_thread().name))
        logging.info("{} ending=======".format(len(cups)))
    
    for x in range(10):
        threading.Thread(target=worker,args=(lock,100)).start()
    
    运行结果:
    INFO:root:0
    INFO:root:Thread-1 make 1........ 
    INFO:root:1
    INFO:root:Thread-5 make 1........ 
    INFO:root:2
    INFO:root:Thread-6 make 1........ 
    ....
    INFO:root:Thread-3 make 1........ 
    INFO:root:97
    INFO:root:Thread-3 make 1........ 
    INFO:root:98
    INFO:root:Thread-4 make 1........ 
    INFO:root:99
    INFO:root:Thread-3 make 1........ 
    INFO:root:100 ending=======
    INFO:root:100 ending=======
    INFO:root:100 ending=======
    .....
    

      在使用了锁以后,虽然保证了结果的准确性,但是性能下降了很多。

     

    一般来说加锁以后还要有一些功能实现,在释放之前还有可能抛异常,一旦抛出异常,锁是无法释放,但是当前线程可能因为这个异常被终止了,这就产生了死锁。

     

    死锁解决办法:

    1、使用 try..except..finally 语句处理异常、保证锁的释放

    2、with 语句上下文管理,锁对象支持上下文管理。只要实现了__enter__和__exit__魔术方法的对象都支持上下文管理。

     

    锁的应用场景:

    独占锁: 锁适用于访问和修改同一个共享资源的时候,即读写同一个资源的时候。

    共享锁: 如果共享资源是不可变的值时,所有线程每一次读取它都是同一样的值,这样的情况就不需要锁。

     

    使用锁的注意事项:

    • 少用锁,必要时用锁。使用了锁,多线程访问被锁的资源时,就变成了串行,要么排队执行,要么争抢执行。
    • 加锁时间越短越好,不需要就立即释放锁。
    • 一定要避免死锁。

    不使用锁时,有了效率,但是结果是错的。

    使用了锁,变成了串行,效率地下,但是结果是对的。

     

    import threading
    import time
    
    lock = threading.Lock()
    
    def work():
        print('working..')
        time.sleep(0.2)
        lock.release() # 1解锁
    
    lock.acquire() # 1上锁
    print("get locker 1")
    
    threading.Thread(target=work).start()
    
    time.sleep(1)
    lock.acquire() # 2上锁
    
    print("get locker 2")
    threading.Thread(target=work).start()
    
    print("release locker")
    
    运行结果:
    get locker 1
    working..
    get locker 2
    working..
    release locker
    

      同一个锁对象在释放后可以再次使用。

    但是如果同一把锁加锁后,又被别人拿了,自己就阻塞了:

    import threading
    import time
    
    lock = threading.Lock()
    
    def work():
        print('working..')
        time.sleep(0.2)
        lock.release() # 1解锁
    
    lock.acquire() # 1上锁
    print("get locker 1")
    lock.acquire() # 2上锁
    print("get locker 2")
    
    threading.Thread(target=work).start()
    threading.Thread(target=work).start()
    
    print("release locker")
    
    运行结果:
    get locker 1
    阻塞状态....
    

      

    阻塞锁:

    #阻塞锁
    import threading,time
    
    lock = threading.Lock()
    
    def foo():
        ret = lock.acquire()
        print("{} Locked. {}".format(ret,threading.current_thread()))
        time.sleep(10)
    
    threading.Thread(target=foo).start()
    threading.Thread(target=foo).start()
    
    运行结果:
    True Locked. <Thread(Thread-1, started 123145559191552)>
    

      lock.acquire()默认设置blocking=True,两个线程使用同一个Lock锁对象,只要Thread-1线程不释放,第二个线程就无法获取锁,且会使Thread-1线程阻塞。

    如果想让多个线程同时都可以使用一个锁对象,就必须使用非阻塞锁,或者第一个线程使用完锁之后立刻释放,然后第二个线程再使用。

     

    非阻塞锁:

    #非阻塞锁
    import threading,time
    
    lock = threading.Lock()
    
    def foo():
        ret = lock.acquire(False)
        print("{} Locked. {}".format(ret,threading.current_thread()))
        time.sleep(10)
    
    threading.Thread(target=foo).start()
    threading.Thread(target=foo).start()
    
    运行结果:
    True Locked. <Thread(Thread-1, started 123145516146688)>
    False Locked. <Thread(Thread-2, started 123145521401856)>
    
    Process finished with exit code 0
    

      lock.acquire(False)设置blocking=False表示不阻塞,使用同一个Lock锁对象时,第二个线程仍可以使用锁,且第一个锁不会被阻塞。

     

    非阻塞锁2:

     

    #非阻塞锁
    import threading,logging,time
    
    FORMAT = '%(asctime)s\t [%(threadName)s,%(thread)d] %(message)s'
    logging.basicConfig(level=logging.INFO,format=FORMAT)
    
    def worker(tasks):
        for task in tasks:
            time.sleep(0.01)
            if task.lock.acquire(False): #False非阻塞
                logging.info('{} {} begin to start'.format(threading.current_thread().name,task.name))
            else:
                logging.info('{} {} is working'.format(threading.current_thread().name,task.name))
    
    class Task:
        def __init__(self,name):
            self.name = name
            self.lock = threading.Lock()
    
    tasks = [Task('task={}'.format(t)) for t in range(5)]
    
    for i in range(3):
        t = threading.Thread(target=worker,name='worker-{}'.format(i),args=(tasks,))
        t.start()
    
    运行结果:
    2017-12-19 16:37:49,556	 [worker-2,123145390018560] worker-2 task=0 begin to start
    2017-12-19 16:37:49,556	 [worker-1,123145384763392] worker-1 task=0 is working
    2017-12-19 16:37:49,557	 [worker-0,123145379508224] worker-0 task=0 is working
    2017-12-19 16:37:49,567	 [worker-2,123145390018560] worker-2 task=1 begin to start
    2017-12-19 16:37:49,567	 [worker-1,123145384763392] worker-1 task=1 is working
    2017-12-19 16:37:49,568	 [worker-0,123145379508224] worker-0 task=1 is working
    2017-12-19 16:37:49,580	 [worker-1,123145384763392] worker-1 task=2 begin to start
    2017-12-19 16:37:49,580	 [worker-2,123145390018560] worker-2 task=2 is working
    2017-12-19 16:37:49,580	 [worker-0,123145379508224] worker-0 task=2 is working
    2017-12-19 16:37:49,591	 [worker-1,123145384763392] worker-1 task=3 begin to start
    2017-12-19 16:37:49,592	 [worker-2,123145390018560] worker-2 task=3 is working
    2017-12-19 16:37:49,592	 [worker-0,123145379508224] worker-0 task=3 is working
    2017-12-19 16:37:49,604	 [worker-1,123145384763392] worker-1 task=4 begin to start
    2017-12-19 16:37:49,604	 [worker-2,123145390018560] worker-2 task=4 is working
    2017-12-19 16:37:49,604	 [worker-0,123145379508224] worker-0 task=4 is working
    

      

     

    转载于:https://www.cnblogs.com/i-honey/p/8065635.html

    展开全文
  • python 进程 线程学习

    2020-12-29 17:30:54
    黑发不知勤学早,白首方悔读书迟。--原作者 什么是多线程竞争?...解释一下什么是锁,几种锁? 锁是python提供的对线程控制的对象。互斥锁,可重入锁,死锁。 互斥锁:同一时刻只允许一个线程操作,具有排他性

    黑发不知勤学早,白首方悔读书迟。--原作者

    什么是多线程竞争?

    线程不是独立的,同一个进程里的线程,线程间的数据是共享的,多线程操作时,容易造成数据的混乱,线程不安全。

    如何解决?

    互斥锁。

    好处:能够保证某段关键代码执行时,只有一个线程操作,保证原子性,避免多线程下的资源竞争。

    坏处:性能下降,阻止了多线程的并发执行。致命问题,有可能产生死锁。

    解释一下什么是锁,有哪几种锁?

    锁是python提供的对线程控制的对象。互斥锁,可重入锁,死锁。

    互斥锁:同一时刻只允许一个线程操作,具有排他性和唯一性。比如A、B两个线程,A操作时,B只能等着,A执行完,B才能操作。

    可重入锁:有时候在同一个线程中,我们可能会多次请求同一资源(就是,获取同一锁钥匙),俗称锁嵌套。

    死锁:互相干等着,都不释放锁,程序无法执行下去。

    GIL锁(全局解释器锁):限制多线程的同时执行,同一时间,只有一个线程执行,所以cpython里的多线程其实是伪多线程。python使用协程代替多线程来解决,更轻量级的线程,进程和线程的切换时系统确定的,而协程的切换是由程序员确定的,而模块gevent下切换是遇到耗时操作才会切换的。进程有线程,线程有协程。

    什么是线程安全,什么是互斥锁?

    作用:保证同一时刻只有一个线程访问一个对象的功能。

    由于同一进程的多个线程之间是共享系统资源的,多个线程同时对一个对象进行操作时,一个线程对其进行操作尚未结束cpu时间片切换到另一个线程对其操作,再切换回来时,数据已被修改,导致结果出现错误。此时需要对被操作的对象添加互斥锁,保证每个线程对该对象的操作都能得到正确的结果。

    说说下面几个概念:同步,异步,阻塞,非阻塞?

    同步:排队,一一执行,一个执行完,才执行下一个。

    异步:没有先后顺序,同时执行。

    阻塞:程序执行到某段,不往下执行了,卡在那里了。

    非阻塞:如果这段卡主了,会执行其他代码。

    什么是僵尸进程和孤儿进程?怎么避免僵尸进程?

    孤儿进程:父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init 进程(进
    程号为1)所收养,并由init 进程对它们完成状态收集工作。
    僵尸进程:在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程

    避免僵尸进程的方法:
    1.fork 两次用孙子进程去完成子进程的任务;
    2.用wait()函数使父进程阻塞;
    3.使用信号量,在signal handler 中调用waitpid,这样父进程不用阻塞。

     

    常见问题总结:

    1. 线程和进程有什么不同?
        ```python
        进程:1>系统进行资源分配和调度的一个独立单元
              2>进程间不共享全局变量,需要进行进程间的通信
              3>进程在运行过程中为独立的内存单元
        线程:1>进程的一个实体,是CPU调度和分派的基本单位
              2>同时对一个全局变量进行修改,容易混乱(不一定执行完就换线程)
              3>线程依赖进程的存在,线程并发性高,占用资源比进程少
              4>多线程共享非全局变量不用加锁
              5>多线程到同一个函数里执行,函数里的变量各是各的
        ```
    2. 什么是单任务、多任务程序?
        ```python
        参考:
        单任务是指一次只能运行一个程序,不能同时运行多个程序
        多任务是指可以同时运行多个程序
        ```
    3. Linux系统是\_\_\_\_任务\_\_\_\_用户的系统?
        ```python
        Linux系统是多任务多用户的系统
        ```
    4. 以单核cpu为例,它是怎样完成多任务的?
        ```python
        轮流切换执行
        微观上,在任何一个时刻只有一个程序被执行
        但切换速度非常的快,因此在宏观上,看上去多个任务在一起执行一样
        ```
    5. 怎样区分并行和并发?
        ```python
        简单来讲:
        并行是指多个cpu同时执行多个任务
        并发是指单个cpu轮流切换执行多个任务
        ```
    6. 程序和进程有什么区别?
        ```python
        简而言之,代码没有被运行之前是一个程序,当运行起来后就能成为进程
        ```
    8. 子进程和父进程是什么?
        ```python
        通过进程a产生的进程b,a进程就是父进程,b就是子进程
        ```
    9. getpid、getppid的作用是什么?
        ```python
        getpid    获取当前进程的进程号
        getppid    获取当前进程的父进程的进程号
        ```
    10. 创建出来的多个子进程,同时对一个相同名字的全局变量操作时会出错么?为什么?
        ```python
        不会出错
        因为进程之间的资源是不共享的,各自拥有各自的一份该变量,操作互不影响
        ```

    12. 创建出来的子进程和父进程到底是谁先执行?为什么?
        ```python
        不确定
        因为多任务中,谁先被执行,是由cpu的调度算法来决定的,cpu会保证每个进程都能被平均的执行一段时间,一次你看上去会是随机的
        ```

    14. multiprocessing模块的目的是什么?
        ```python
        使用multiprocessing模块中的Process创建一个子进程
        ```
    15. 怎样用multiprocessing模块中的Process创建一个子进程?请写出基本代码
       

     

    from multiprocessing import Process
        def mission():
            for i in range(5):
                print(i)
        if __name__ == "__main__":
            p = Process(target=mission)    # 创建进程实例
            p.start()    # 启动子进程
            p.join()    # 让父进程等待
    

    16. multiprocessing模块中的Process创建了一个子进程后,怎样让子进程开始执行?
        ```python
        调用start方法
        ```

    18. 如果一个程序需要同时执行多个任务,那么一般会怎么做?
        ```python
        使用多进程或者多线程来实现
        ```

    20. 什么是进程池?有什么用?
        ```python
        进程池就是创建出一定固定数量的进程,去执行多个任务
        节约创建进程和销毁进程所消耗的资源和空间
        当某个任务被执行完毕后,利用该进程再去执行其他的任务,大大提高效率
        ```

    19. 为了完成多个任务一起执行,可以创建多个子进程来执行任务,那么为什么还要进程池呢?
        ```python
        因为每创建一个进程都会申请内存空间,消耗资源,进程结束又要回收资源
        如果反复创建进程,又结束进程,会严重影响性能
        进程池的目的就是复用进程,大大提高程序的运行效率
        ```

    21. 什么是进程间通信?
        ```python
        简而言之
        进程间的资源是不共享的,因此如果在不同进程间的任务需要相互使用对方的资源或信息
        那么就需要在进程之间传递信息、传递资源,这就是进程间通信
        ```

    22. 为什么需要进程间通信?
        ```python
        同上
        ```

    23. multiprocessing模块中Queue怎样发送、取出数据?
        ```python
        q = Queue()
        q.put(数据)  # 存放数据
        q.get()  # 取出数据
        ```

    # 关卡二

    练习题:1. 使用Process创建1个子进程,让子进程每1秒钟打印1个数字,数字从1开始一直到10,即1.2.3......10
        

     

        # coding=utf-8
        import time
        from multiprocessing import Process
        # 定义子进程的需要执行的任务 函数
        def mission():
            #打印1-10
            for i in range(1,11):
                print(i)
                time.sleep(1)
    
        def main():
            p = Process(target=mission)
            p.start()
            p.join()
        if __name__ == "__main__":
            main() 


    2. 使用multiprocessing模块中的Queue,完成子进程中将hello传递到父进程中,父进程打印出来
     

     

        # coding=utf-8
        import time
        from multiprocessing import Process, Queue
        # 定义父进程的需要执行的任务 函数
        def parent_mission(que):
            data = que.get()    # 从队列获取数据打印
            print(data)
            time.sleep(5)
    
        # 定义子进程的需要执行的任务 函数   
        def children_mission(que):
            data = "hello"   # 输入hello就会被父进程拿到
            que.put(data)    #  往队列添加数据
            time.sleep(3)
    
        def main():
            q = Queue()    # 在父进程中定义队列,实现与子进程通信
            p = Process(target=children_mission, args=(q,))
            p.start()    # 启动子进程 执行任务
            parent_mission(q)    # 在父进程中 执行任务
            p.join()
        if __name__ == "__main__":
            main()    

    1. 使用进程池完成如下要求:
        * 将/usr/lib/python3.5文件夹下的所有py结尾的文件copy到 桌面上的Test文件夹中
        * 用多任务(多进程或者多线程)的方式完成Test文件夹中的所有内容复制
        * 新的文件夹的名字为“Test-附件”
        * 在复制文件的过程中,实时显示复制的进度

     

    import multiprocessing
    import os
    import time
    import random
    
    
    def copy_file(queue, file_name,source_folder_name,  dest_folder_name):
        """copy文件到指定的路径"""
        f_read = open(source_folder_name + "/" + file_name, "rb")
        f_write = open(dest_folder_name + "/" + file_name, "wb")
        while True:
            time.sleep(random.random())
            content = f_read.read(1024)
            if content:
                f_write.write(content)
            else:
                break
        f_read.close()
        f_write.close()
    
        # 发送已经拷贝完毕的文件名字
        queue.put(file_name)
    
    
    def main():
        # 获取要复制的文件夹
        source_folder_name = input("请输入要复制文件夹名字:")
    
        # 整理目标文件夹
        dest_folder_name = source_folder_name + "[副本]"
    
        # 创建目标文件夹
        try:
            os.mkdir(dest_folder_name)
        except:
            pass  # 如果文件夹已经存在,那么创建会失败
    
        # 获取这个文件夹中所有的普通文件名
        file_names = os.listdir(source_folder_name)
    
        # 创建Queue
        queue = multiprocessing.Manager().Queue()
    
        # 创建进程池
        pool = multiprocessing.Pool(3)
    
        for file_name in file_names:
            # 向进程池中添加任务
            pool.apply_async(copy_file, args=(queue, file_name, source_folder_name, dest_folder_name))
    
        # 主进程显示进度
        pool.close()
    
        all_file_num = len(file_names)
        while True:
            file_name = queue.get()
            if file_name in file_names:
                file_names.remove(file_name)
    
            copy_rate = (all_file_num-len(file_names))*100/all_file_num
            print("\r%.2f...(%s)" % (copy_rate, file_name) + " "*50, end="")
            if copy_rate >= 100:
                break
        print()
    
    
    if __name__ == "__main__":
        main()

     

     

     

     

    什么是多线程竞争?

    线程不是独立的,同一个进程里的线程,线程间的数据是共享的,多线程操作时,容易造成数据的混乱,线程不安全。

    如何解决?

    互斥锁。

    好处:能够保证某段关键代码执行时,只有一个线程操作,保证原子性,避免多线程下的资源竞争。

    坏处:性能下降,阻止了多线程的并发执行。致命问题,有可能产生死锁。

    解释一下什么是锁,有哪几种锁?

    锁是python提供的对线程控制的对象。互斥锁,可重入锁,死锁。

    互斥锁:同一时刻只允许一个线程操作,具有排他性和唯一性。比如A、B两个线程,A操作时,B只能等着,A执行完,B才能操作。

    可重入锁:有时候在同一个线程中,我们可能会多次请求同一资源(就是,获取同一锁钥匙),俗称锁嵌套。

    死锁:互相干等着,都不释放锁,程序无法执行下去。

    GIL锁(全局解释器锁):限制多线程的同时执行,同一时间,只有一个线程执行,所以cpython里的多线程其实是伪多线程。python使用协程代替多线程来解决,更轻量级的线程,进程和线程的切换时系统确定的,而协程的切换是由程序员确定的,而模块gevent下切换是遇到耗时操作才会切换的。进程有线程,线程有协程。

    什么是线程安全,什么是互斥锁?

    作用:保证同一时刻只有一个线程访问一个对象的功能。

    由于同一进程的多个线程之间是共享系统资源的,多个线程同时对一个对象进行操作时,一个线程对其进行操作尚未结束cpu时间片切换到另一个线程对其操作,再切换回来时,数据已被修改,导致结果出现错误。此时需要对被操作的对象添加互斥锁,保证每个线程对该对象的操作都能得到正确的结果。

    说说下面几个概念:同步,异步,阻塞,非阻塞?

    同步:排队,一一执行,一个执行完,才执行下一个。

    异步:没有先后顺序,同时执行。

    阻塞:程序执行到某段,不往下执行了,卡在那里了。

    非阻塞:如果这段卡主了,会执行其他代码。

    什么是僵尸进程和孤儿进程?怎么避免僵尸进程?

    孤儿进程:父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init 进程(进
    程号为1)所收养,并由init 进程对它们完成状态收集工作。
    僵尸进程:在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程。

    避免僵尸进程的方法:
    1.fork 两次用孙子进程去完成子进程的任务;
    2.用wait()函数使父进程阻塞;
    3.使用信号量,在signal handler 中调用waitpid,这样父进程不用阻塞。

     

    常见问题总结:

    1. 线程和进程有什么不同?
        ```python
        进程:1>系统进行资源分配和调度的一个独立单元
              2>进程间不共享全局变量,需要进行进程间的通信
              3>进程在运行过程中为独立的内存单元
        线程:1>进程的一个实体,是CPU调度和分派的基本单位
              2>同时对一个全局变量进行修改,容易混乱(不一定执行完就换线程)
              3>线程依赖进程的存在,线程并发性高,占用资源比进程少
              4>多线程共享非全局变量不用加锁
              5>多线程到同一个函数里执行,函数里的变量各是各的
        ```
    2. 什么是单任务、多任务程序?
        ```python
        参考:
        单任务是指一次只能运行一个程序,不能同时运行多个程序
        多任务是指可以同时运行多个程序
        ```
    3. Linux系统是\_\_\_\_任务\_\_\_\_用户的系统?
        ```python
        Linux系统是多任务多用户的系统
        ```
    4. 以单核cpu为例,它是怎样完成多任务的?
        ```python
        轮流切换执行
        微观上,在任何一个时刻只有一个程序被执行
        但切换速度非常的快,因此在宏观上,看上去多个任务在一起执行一样
        ```
    5. 怎样区分并行和并发?
        ```python
        简单来讲:
        并行是指多个cpu同时执行多个任务
        并发是指单个cpu轮流切换执行多个任务
        ```
    6. 程序和进程有什么区别?
        ```python
        简而言之,代码没有被运行之前是一个程序,当运行起来后就能成为进程
        ```
    8. 子进程和父进程是什么?
        ```python
        通过进程a产生的进程b,a进程就是父进程,b就是子进程
        ```
    9. getpid、getppid的作用是什么?
        ```python
        getpid    获取当前进程的进程号
        getppid    获取当前进程的父进程的进程号
        ```
    10. 创建出来的多个子进程,同时对一个相同名字的全局变量操作时会出错么?为什么?
        ```python
        不会出错
        因为进程之间的资源是不共享的,各自拥有各自的一份该变量,操作互不影响
        ```

    12. 创建出来的子进程和父进程到底是谁先执行?为什么?
        ```python
        不确定
        因为多任务中,谁先被执行,是由cpu的调度算法来决定的,cpu会保证每个进程都能被平均的执行一段时间,一次你看上去会是随机的
        ```

    14. multiprocessing模块的目的是什么?
        ```python
        使用multiprocessing模块中的Process创建一个子进程
        ```
    15. 怎样用multiprocessing模块中的Process创建一个子进程?请写出基本代码
       

     
    from multiprocessing import Process
     
    def mission():
     
            for i in range(5):
     
                print(i)
     
    if __name__ == "__main__":
     
            p = Process(target=mission)    # 创建进程实例
     
            p.start()    # 启动子进程
     
            p.join()    # 让父进程等待

    16. multiprocessing模块中的Process创建了一个子进程后,怎样让子进程开始执行?
        ```python
        调用start方法
        ```

    18. 如果一个程序需要同时执行多个任务,那么一般会怎么做?
        ```python
        使用多进程或者多线程来实现
        ```

    20. 什么是进程池?有什么用?
        ```python
        进程池就是创建出一定固定数量的进程,去执行多个任务
        节约创建进程和销毁进程所消耗的资源和空间
        当某个任务被执行完毕后,利用该进程再去执行其他的任务,大大提高效率
        ```

    19. 为了完成多个任务一起执行,可以创建多个子进程来执行任务,那么为什么还要进程池呢?
        ```python
        因为每创建一个进程都会申请内存空间,消耗资源,进程结束又要回收资源
        如果反复创建进程,又结束进程,会严重影响性能
        进程池的目的就是复用进程,大大提高程序的运行效率
        ```

    21. 什么是进程间通信?
        ```python
        简而言之
        进程间的资源是不共享的,因此如果在不同进程间的任务需要相互使用对方的资源或信息
        那么就需要在进程之间传递信息、传递资源,这就是进程间通信
        ```

    22. 为什么需要进程间通信?
        ```python
        同上
        ```

    23. multiprocessing模块中Queue怎样发送、取出数据?
        ```python
        q = Queue()
        q.put(数据)  # 存放数据
        q.get()  # 取出数据
        ```

    # 关卡二

    练习题:1. 使用Process创建1个子进程,让子进程每1秒钟打印1个数字,数字从1开始一直到10,即1.2.3......10
        

    # coding=utf-8
     
        import time
     
        from multiprocessing import Process
     
        # 定义子进程的需要执行的任务 函数
     
        def mission():
     
            #打印1-10
     
            for i in range(1,11):
     
                print(i)
     
                time.sleep(1)
      
     
        def main():
     
            p = Process(target=mission)
     
            p.start()
     
            p.join()
     
        if __name__ == "__main__":
     
            main() 

    2. 使用multiprocessing模块中的Queue,完成子进程中将hello传递到父进程中,父进程打印出来
     

    # coding=utf-8
     
        import time
     
        from multiprocessing import Process, Queue
     
        # 定义父进程的需要执行的任务 函数
     
        def parent_mission(que):
     
            data = que.get()    # 从队列获取数据打印
     
            print(data)
     
            time.sleep(5)
      
     
        # 定义子进程的需要执行的任务 函数   
     
        def children_mission(que):
     
            data = "hello"   # 输入hello就会被父进程拿到
     
            que.put(data)    #  往队列添加数据
     
            time.sleep(3)
      
     
        def main():
     
            q = Queue()    # 在父进程中定义队列,实现与子进程通信
     
            p = Process(target=children_mission, args=(q,))
     
            p.start()    # 启动子进程 执行任务
     
            parent_mission(q)    # 在父进程中 执行任务
     
            p.join()
     
        if __name__ == "__main__":
     
            main()  

     

    1. 使用进程池完成如下要求:
        * 将/usr/lib/python3.5文件夹下的所有py结尾的文件copy到 桌面上的Test文件夹中
        * 用多任务(多进程或者多线程)的方式完成Test文件夹中的所有内容复制
        * 新的文件夹的名字为“Test-附件”
        * 在复制文件的过程中,实时显示复制的进度

      

    import multiprocessing
    import os
    import time
    import random
    
    
    def copy_file(queue, file_name,source_folder_name,  dest_folder_name):
        """copy文件到指定的路径"""
        f_read = open(source_folder_name + "/" + file_name, "rb")
        f_write = open(dest_folder_name + "/" + file_name, "wb")
        while True:
            time.sleep(random.random())
            content = f_read.read(1024)
            if content:
                f_write.write(content)
            else:
                break
        f_read.close()
        f_write.close()
    
        # 发送已经拷贝完毕的文件名字
        queue.put(file_name)
    
    
    def main():
        # 获取要复制的文件夹
        source_folder_name = input("请输入要复制文件夹名字:")
    
        # 整理目标文件夹
        dest_folder_name = source_folder_name + "[副本]"
    
        # 创建目标文件夹
        try:
            os.mkdir(dest_folder_name)
        except:
            pass  # 如果文件夹已经存在,那么创建会失败
    
        # 获取这个文件夹中所有的普通文件名
        file_names = os.listdir(source_folder_name)
    
        # 创建Queue
        queue = multiprocessing.Manager().Queue()
    
        # 创建进程池
        pool = multiprocessing.Pool(3)
    
        for file_name in file_names:
            # 向进程池中添加任务
            pool.apply_async(copy_file, args=(queue, file_name, source_folder_name, dest_folder_name))
    
        # 主进程显示进度
        pool.close()
    
        all_file_num = len(file_names)
        while True:
            file_name = queue.get()
            if file_name in file_names:
                file_names.remove(file_name)
    
            copy_rate = (all_file_num-len(file_names))*100/all_file_num
            print("\r%.2f...(%s)" % (copy_rate, file_name) + " "*50, end="")
            if copy_rate >= 100:
                break
        print()
    
    
    if __name__ == "__main__":
        main()

     

    展开全文
  • GIL:又叫全局解释器,每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程在运行,目的是解决多线程同时竞争程序中的全局变量而出现的线程安全问题。它并不是python语言的特性,仅仅是由于历史的...
  • 编写一个多线程抓取网页的程序,并阐明多线程抓取程序是否可比单线程性能提升,并解释原因。 GIL:又叫全局解释器,每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程在运行,目的是解决多线程...
  • Python的多线程在io方面比单线程还是优势,但是在多线程开发...参数 operation 指定要进行的操作,该参数的取值如下几种: LOCK_SH:表示要创建一个共享,在任意时间内,一个文件的共享可以被多个进程拥有 L
  • 什么是多线程竞争? 线程不是独立的,同一个进程里的线程线程间的数据是共享的,多线程操作时,容易造成数据的混乱,线程不安全。...解释一下什么是锁,几种锁? 锁是python提供的对线程控制的对象。互斥锁,...
  • 有几种方法:算法优化、激发CPUGPU的力量等。 我现在分享关于python线程多进程的方式和心得,用于激发电脑性能。Threadfrom threading import Thread任何优化方式都有自己的局限性,python3由于GIL机制的问题,...
  • 不同Linux系统下提供的底层线程有几种,其中POSIX类型的线程最为常用。POSIX线程是pthread开头的一系列C语言API,数据结构包括mutex,condition等。C语言多线程不是必须的,只在一些场合适用,而例如单线程的...
  • 线程线程的同步

    2017-12-27 10:53:29
    二、线程同步的几种方法 线程同步很多种方法,以下介绍三种方法:同步、信号量、Events事件。 三、同步 1、基本原理 Python的threading模块提供的最基本的同步机制。在任一时刻,一个对象可能被一个...
  • python 防死锁机制

    2018-12-26 15:59:00
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在编写多线程程序时,可能无意中就会写了一个死锁。可以说,死锁的形式...以本人的经验总结,死锁通常以下几种 同一线程,嵌套获取同把,造成死锁。 多个线程,不按顺序同...
  • 单例模式你会几种写法? 工厂模式理解了没有? 策略模式原来就这么简单! 三分钟学会门面模式! 一分钟学会《模板方法模式》 这就是『责任链模式』? 责任链模式通用代码 建造者模式 :guitar:HTTP+JSON+XML 30页...
  • 并发编程二

    2019-09-22 23:47:50
    一.GIL全局解释器锁 ... python解释器锁有很多,Jpython Ppython 最常见的就是Cpython  GIL其实本质也是一把互斥锁:用来阻止线程同时操作同一份数据,对于被操作的数据加锁  由并发变成了串行,虽然牺...
  • 某东公司的面试题

    千次阅读 2015-01-18 20:34:12
    由于最近比较躁动,动了跳槽的念想,于是便有了这次经历,在这里记录下来,分享给大家。好了废话不多说,开始正文。...3.Java中内存泄露有几种?如何分析泄露原因? 4.UI线程与非UI线程区别?如何交
  • 4.4.5 JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的JVM参数。 4.4.6 你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。 4.4.7 垃圾回收算法的...
  • 基础15 Elastic Search 基于external version进行乐观并发控制 基础16 Elastic Search partial update 基础17 Elastic Search 基于groovy脚本进行partial update 基础18 Elastic Search mget批量查询api ...
  • 不可不说的几种限流算法 ThreadPoolExecutor类的核心流程 ThreadLocal学会了这些,你也能和面试官扯皮了! 高并发秒杀系统架构解密,不是所有的秒杀都是秒杀! 高并发环境下诡异的加锁问题(你加的未必安全) 什么...
  • 我建议如果是python的话,了解urllib(http请求),requests(http请求),lxml(文本解析),Scrapy(爬虫框架),多线程爬虫就可以了 原来也在csdn上写过一些scrapy的文章,当然学习一门语言官方文档才是最重要的...
  • 敏捷软件开发中可能是最富有成效的几种方法学之一 技能图谱 backend skill 后台开发技能图谱,从程序员的内功修炼到后台语言,分布式系统架构 一、数据结构与算法 数据结构与算法  排序算法、动态规划、...
  • 敏捷软件开发中可能是最富有成效的几种方法学之一 技能图谱 backend skill 后台开发技能图谱,从程序员的内功修炼到后台语言,分布式系统架构 一、数据结构与算法 数据结构与算法  排序算法、动态规划、...
  • sesvc.exe 阿萨德

    2019-06-02 17:11:12
    和 1.7 大体上都差不多,还是有几个重要的区别: TREEIFY_THRESHOLD 用于判断是否需要将链表转换为红黑树的阈值。 HashEntry 修改为 Node。 Node 的核心组成其实也是和 1.7 中的 HashEntry 一样,存放的都是 key ...
  • 如果你已经有几年的编码经验,又想把代码写好,建议你多挑基本读读,吸收每本书的精华。 计算机网络 学什么? 计算网络的协议非常非常多,很多同学学完都一头雾水,或者仅仅懂一点 HTTP,但是真正要掌握的东西可...
  • c++如何实现多态,有几种方式,动态多态和静态多态区别 模板了解嘛 c++继承多态 c++深拷贝与浅拷贝 拷贝构造函数和委托构造函数 c++面向对象 右值引用,move语义,完美转发 emplace_back和push_back区别 ...
  • 推荐个炫酷的Python开源项目 书籍推荐 我的Java后端开发小书架分享 必读计算机编程好书推荐!程序员小伙搬出了他的书架! 自学C/C++书籍推荐(自学C/C++看书路线推荐) 自学编程 编程基础! 基本功趣味...
  • CVE-2020-2546,CVE-2020-2915 CVE-2020-2801 CVE-2020-2798 CVE-2020-2883 CVE-2020-2884 CVE-2020-2950 WebLogic T3 payload exploit poc python3|CVE-2020-2883-Weblogic coherence.jar RCE|WebLogic-Shiro-shell...

空空如也

空空如也

1 2
收藏数 32
精华内容 12
关键字:

python线程锁有几种锁

python 订阅