zoukankan      html  css  js  c++  java
  • python-day9-进程、线程、协程篇

    python threading模块

    线程有两种调用方式:

    直接调用

    import threading
    import time
     
    def sayhi(num): #定义每个线程要运行的函数
     
        print("running on number:%s" %num)
     
        time.sleep(3)
     
    if __name__ == '__main__':
     
        t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
        t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
     
        t1.start() #启动线程
        t2.start() #启动另一个线程
     
        print(t1.getName()) #获取线程名
        print(t2.getName())

    继承调用

    import threading
    import time
     
     
    class MyThread(threading.Thread):
        def __init__(self,num):
            threading.Thread.__init__(self)
            self.num = num
     
        def run(self):#定义每个线程要运行的函数
     
            print("running on number:%s" %self.num)
     
            time.sleep(3)
     
    if __name__ == '__main__':
     
        t1 = MyThread(1)
        t2 = MyThread(2)
        t1.start()
        t2.start()

    Join & Daemon

    #_*_coding:utf-8_*_
    __author__ = 'liudong'
     
    import time
    import threading
     
     
    def run(n):
     
        print('[%s]------running----
    ' % n)
        time.sleep(2)
        print('--done--')
     
    def main():
        for i in range(5):
            t = threading.Thread(target=run,args=[i,])
            t.start()
            t.join(1)
            print('starting thread', t.getName())
     
     
    m = threading.Thread(target=main,args=[])
    m.setDaemon(True) #将main线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,m线程也会退出,由m启动的其它子线程会同时退出,不管是否执行完任务
    m.start()
    m.join(timeout=2)
    print("---main thread done----")

    线程锁(互斥锁Mutex)

    一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,会出现什么状况?

    import time
    import threading
     
    def addNum():
        global num #在每个线程中都获取这个全局变量
        print('--get num:',num )
        time.sleep(1)
        num  -=1 #对此公共变量进行-1操作
     
    num = 100  #设定一个共享变量
    thread_list = []
    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 )

    正常来讲,这个num结果应该是0, 但在python 2.7上多运行几次,会发现,最后打印出来的num结果不总是0,为什么每次运行的结果不一样呢? 哈,很简单,假设你有A,B两个线程,此时都 要对num 进行减1操作, 由于2个线程是并发同时运行的,所以2个线程很有可能同时拿走了num=100这个初始变量交给cpu去运算,当A线程去处完的结果是99,但此时B线程运算完的结果也是99,两个线程同时CPU运算的结果再赋值给num变量后,结果就都是99。那怎么办呢? 很简单,每个线程在要修改公共数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。 

    *注:不要在3.x上运行,不知为什么,3.x上的结果总是正确的,可能是自动加了锁

    加锁版本:

    import time
    import threading
     
    def addNum():
        global num #在每个线程中都获取这个全局变量
        print('--get num:',num )
        time.sleep(1)
        lock.acquire() #修改数据前加锁
        num  -=1 #对此公共变量进行-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 )
     

    GIL VS Lock 

    流程图

    RLock(递归锁)

    import threading,time
     
    def run1():
        print("grab the first part data")
        lock.acquire()
        global num
        num +=1
        lock.release()
        return num
    def run2():
        print("grab the second part data")
        lock.acquire()
        global  num2
        num2+=1
        lock.release()
        return num2
    def run3():
        lock.acquire()
        res = run1()
        print('--------between run1 and run2-----')
        res2 = run2()
        lock.release()
        print(res,res2)
     
     
    if __name__ == '__main__':
     
        num,num2 = 0,0
        lock = threading.RLock()
        for i in range(10):
            t = threading.Thread(target=run3)
            t.start()
     
    while threading.active_count() != 1:
        print(threading.active_count())
    else:
        print('----all threads done---')
        print(num,num2)

    Semaphore(信号量)

    互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据。

    import threading,time
     
    def run(n):
        semaphore.acquire()
        time.sleep(1)
        print("run the thread: %s
    " %n)
        semaphore.release()
     
    if __name__ == '__main__':
     
        num= 0
        semaphore  = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
        for i in range(20):
            t = threading.Thread(target=run,args=(i,))
            t.start()
     
    while threading.active_count() != 1:
        pass #print threading.active_count()
    else:
        print('----all threads done---')
        print(num)

    同时启动50个进程统计时间:

    import threading
    import time
    def run(n):
        print("task" ,n)
        time.sleep(2)
        print("task done",n,threading.current_thread())
    #同时启动50个进程 计算时间
    start_time = time.time()
    t_objs = []#存线程实例
    for i in range(50):
        t = threading.Thread(target=run,args=("t-%s" %i ,))
        t.setDaemon(True)#把当前线程设置为守护线程
        t.start()
        t_objs.append(t)#为了不阻塞后面的线程,在这里不join,写到一个列表里
    #for t in t_objs:
    #    t.join()
    #time.sleep(2)
    print("-----------------------")
    print("cost:",time.time() - start_time)

    Events

    通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。

    import threading,time
    import random
    def light():
        if not event.isSet():
            event.set() #wait就不阻塞 #绿灯状态
        count = 0
        while True:
            if count < 10:
                print('33[42;1m--green light on---33[0m')
            elif count <13:
                print('33[43;1m--yellow light on---33[0m')
            elif count <20:
                if event.isSet():
                    event.clear()
                print('33[41;1m--red light on---33[0m')
            else:
                count = 0
                event.set() #打开绿灯
            time.sleep(1)
            count +=1
    def car(n):
        while 1:
            time.sleep(random.randrange(10))
            if  event.isSet(): #绿灯
                print("car [%s] is running.." % n)
            else:
                print("car [%s] is waiting for the red light.." %n)
    if __name__ == '__main__':
        event = threading.Event()
        Light = threading.Thread(target=light)
        Light.start()
        for i in range(3):
            t = threading.Thread(target=car,args=(i,))
            t.start()

    这里还有一个event使用的例子,员工进公司门要刷卡, 我们这里设置一个线程是“门”, 再设置几个线程为“员工”,员工看到门没打开,就刷卡,刷完卡,门开了,员工就可以通过。

    #_*_coding:utf-8_*_
    __author__ = 'Alex Li'
    import threading
    import time
    import random
    
    def door():
        door_open_time_counter = 0
        while True:
            if door_swiping_event.is_set():
                print("33[32;1mdoor opening....33[0m")
                door_open_time_counter +=1
    
            else:
                print("33[31;1mdoor closed...., swipe to open.33[0m")
                door_open_time_counter = 0 #清空计时器
                door_swiping_event.wait()
    
    
            if door_open_time_counter > 3:#门开了已经3s了,该关了
                door_swiping_event.clear()
    
            time.sleep(0.5)
    
    
    def staff(n):
    
        print("staff [%s] is comming..." % n )
        while True:
            if door_swiping_event.is_set():
                print("33[34;1mdoor is opened, passing.....33[0m")
                break
            else:
                print("staff [%s] sees door got closed, swipping the card....." % n)
                print(door_swiping_event.set())
                door_swiping_event.set()
                print("after set ",door_swiping_event.set())
            time.sleep(0.5)
    door_swiping_event  = threading.Event() #设置事件
    
    
    door_thread = threading.Thread(target=door)
    door_thread.start()
    
    
    
    for i in range(5):
        p = threading.Thread(target=staff,args=(i,))
        time.sleep(random.randrange(3))
        p.start()
    View Code

    queue队列 

    queue is especially useful in threaded programming when information must be exchanged safely between multiple threads.

    class queue.Queue(maxsize=0) #先入先出
    class queue.LifoQueue(maxsize=0) #last in fisrt out 
    class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

    Constructor for a priority queue. maxsize is an integer that sets the upperbound limit on the number of items that can be placed in the queue. Insertion will block once this size has been reached, until queue items are consumed. If maxsize is less than or equal to zero, the queue size is infinite.

    The lowest valued entries are retrieved first (the lowest valued entry is the one returned by sorted(list(entries))[0]). A typical pattern for entries is a tuple in the form: (priority_number, data).

    exception queue.Empty

    Exception raised when non-blocking get() (or get_nowait()) is called on a Queue object which is empty.

    exception queue.Full

    Exception raised when non-blocking put() (or put_nowait()) is called on a Queue object which is full.

    Queue.qsize()
    Queue.empty() #return True if empty  
    Queue.full() # return True if full 
    Queue.put(itemblock=Truetimeout=None)

    Put item into the queue. If optional args block is true and timeout is None (the default), block if necessary until a free slot is available. If timeout is a positive number, it blocks at most timeout seconds and raises the Full exception if no free slot was available within that time. Otherwise (block is false), put an item on the queue if a free slot is immediately available, else raise the Full exception (timeout is ignored in that case).

    Queue.put_nowait(item)

    Equivalent to put(item, False).

    Queue.get(block=Truetimeout=None)

    Remove and return an item from the queue. If optional args block is true and timeout is None (the default), block if necessary until an item is available. If timeout is a positive number, it blocks at most timeout seconds and raises the Empty exception if no item was available within that time. Otherwise (block is false), return an item if one is immediately available, else raise the Empty exception (timeout is ignored in that case).

    Queue.get_nowait()

    Equivalent to get(False).

    Two methods are offered to support tracking whether enqueued tasks have been fully processed by daemon consumer threads.

    Queue.task_done()

    Indicate that a formerly enqueued task is complete. Used by queue consumer threads. For each get() used to fetch a task, a subsequent call to task_done() tells the queue that the processing on the task is complete.

    If a join() is currently blocking, it will resume when all items have been processed (meaning that a task_done() call was received for every item that had been put() into the queue).

    Raises a ValueError if called more times than there were items placed in the queue.

    Queue.join() block直到queue被消费完毕

    生产者消费者模型

    在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

    为什么要使用生产者和消费者模式

    在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

    什么是生产者消费者模式

    生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

    下面来学习一个最基本的生产者消费者模型的例子

    import threading
    import queue
    
    def producer():
        for i in range(10):
            q.put("骨头 %s" % i )
    
        print("开始等待所有的骨头被取走...")
        q.join()
        print("所有的骨头被取完了...")
    
    
    def consumer(n):
    
        while q.qsize() >0:
    
            print("%s 取到" %n  , q.get())
            q.task_done() #告知这个任务执行完了
    
    
    q = queue.Queue()
    
    
    
    p = threading.Thread(target=producer,)
    p.start()
    
    c1 = consumer("test")
    import time,random
    import queue,threading
    q = queue.Queue()
    def Producer(name):
      count = 0
      while count <20:
        time.sleep(random.randrange(3))
        q.put(count)
        print('Producer %s has produced %s baozi..' %(name, count))
        count +=1
    def Consumer(name):
      count = 0
      while count <20:
        time.sleep(random.randrange(4))
        if not q.empty():
            data = q.get()
            print(data)
            print('33[32;1mConsumer %s has eat %s baozi...33[0m' %(name, data))
        else:
            print("-----no baozi anymore----")
        count +=1
    p1 = threading.Thread(target=Producer, args=('A',))
    c1 = threading.Thread(target=Consumer, args=('B',))
    p1.start()
    c1.start()
    View Code

    远程ssh连接返回执行命令结果

    import paramiko
    #pricate_key = paramiko.RSAKey.from_private_key_file('key路径.ssh/id_rsa')
    #创建ssh对象
    ssh = paramiko.SSHClient()
    #允许连接不在know_hosts文件的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    #连接服务器
    ssh.connect(hostname='111.206.164.194',port=31961,username='work',password='bnm49a52e27')
    #pkey
    #ssh.connect(hostname='111.206.164.194',port=31961,username='work', pkey=pricate_key)
    #执行命令
    stdin, stdout, stderr=ssh.exec_command('df')
    #获取正确命令结果
    result = stdout.read()
    print(result.decode())
    #获取错误命令结果
    #result = stderr.read()
    #print(result.decode())
    #关闭连接
    ssh.close()

    paramiko模块

    ssh_ftp_上传下载:

    __author__="liudong"
    
    import paramiko
    transport = paramiko.Transport(('111.206.164.194',31961))
    transport.connect(username='work',password='bnm49a52e27')
    sftp = paramiko.SFTPClient.from_transport(transport)
    
    #上传
    #sftp.put('bi_ji.py','/tmp/liudong.py')
    #下载
    sftp.get('/tmp/liudong.py','C:/Users/dong/PycharmProjects/untitled1/s14/day9/123.py')
    
    transport.close()
  • 相关阅读:
    CSS文本部分之字体样式[1]
    CSS基础之简单介绍
    [09]HTML基础之全局属性
    [08]HTML基础之视频标签
    [07]HTML基础之图片标签
    [06]HTML基础之表单标签
    [05]HTML基础之表格标签
    sonarqube启动报错
    rhel6下kvm克隆后的操作登录新克隆的虚拟机重新配置网络
    解决KVM 宿主机redhat6系统上shutdown关不了虚拟机的问题
  • 原文地址:https://www.cnblogs.com/liuyansheng/p/5888936.html
Copyright © 2011-2022 走看看