python学习笔记9--paramiko模块、多线程、锁机制

一、paramiko模块

  paramiko模块是一个遵循ssh2协议的python扩展模块,该模块可以允许使用python通过ssh协议去远程管理主机。在使用该模块前,需要手动安装,具体安装过程请百度,这里不再赘述。

  通过paramiko模块不仅可以远程连接主机执行命令,还可以远程传输文件,类似与scp功能。接下来我们分别来看一下使用paramiko模块来实现模拟ssh和scp这两个功能的实现步骤及代码:

  模拟ssh登录的步骤:

  1、实例化一个ssh对象:ssh = paramiko.SSHClient

  2、保存远程主机的公钥信息到known_hosts文件中:ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

  3、连接主机:ssh.connect(hostname="IP",port="端口",username="用户名",password="密码")

  4、收集命令标准输入、标准输出、标准错误信息:stdin,stdout,stderr = ssh.exec_command('命令')

  5、处理命令输出结果

  6、关闭连接:ssh.close()

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='10.1.16.203',port=22,username="zhanghaoyan",password="zhy200")

stdin,stdout,stderr = ssh.exec_command("top")
res,err = stdout.read(),stderr.read()
result = res if res else err
print(result.decode())
ssh.close()
ssh密码认证

  模拟scp传文件的步骤:

  1、实例化一个transport对象:transport = paramiko.Transport(('hostname',port))

  2、连接服务器:transport.connect(username='用户名',password='密码')

  3、将该transport实例作为参数传递给SFTPClient.from_transport()来创建一个sftp实例:sftp = paramiko.SFTPClient.from_transport(transport)

  4、上传文件/下载文件:sftp.put("本地文件","目标路径")/sftp.get("目标路径","本地路径")

  5、关闭连接:transport.close()

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import paramiko

transport = paramiko.Transport(('10.1.16.203',22))
transport.connect(username="zhanghaoyan",password='zhy200')

sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put("./note","/tmp/note.txt")    #上传文件
#sftp.get("/home/zhanghaoyan/codes/a.txt","./")    #下载文件
transport.close()
传输文件

 

  paramiko模块还可以使用秘钥认证的方式去登陆管理服务器,实现步骤如下:

  1、指定本地公钥文件:pri_key = paramiko.RSAKey.from_private_key_file("公钥文件路径")

  2、连接时password参数改为pkey参数,传入上述定义的公钥文件变量ssh.connect(hostname="IP地址",port=端口号,username="用户名",pkey=秘钥变量)

  3、其余步骤参照上述ssh部分

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import paramiko

pri_key = paramiko.RSAKey.from_private_key_file("/home/zhanghaoyan/.ssh/id_rsa")
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname="10.1.16.203",port=22,username="zhanghaoyan",pkey=pri_key)
stdin,stdout,stderr = ssh.exec_command("ls")
res,err = stdout.read(),stderr.read()
result = res if res else err
print(result.decode())
ssh.close()
免密码ssh认证
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import paramiko

pri_key = paramiko.RSAKey.from_private_key_file("/Users/zhanghaoyan/.ssh/id_rsa")
transport = paramiko.Transport(('10.1.16.203',22))
transport.connect(username="zhanghaoyan",pkey=pri_key)

sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put("./note","/tmp/note.txt")
transport.close()
免密码scp传输文件

 二、线程

  1、什么是线程

  线程就是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

  A thread is an execution context, which is all the information a CPU needs to execute a stream of instructions.Suppose you're reading a book, and you want to take a break right now, but you want to be able to come back and resume reading from the exact point where you stopped.One way to achieve that is by jotting down the page number, line number, and word number.So your execution context for reading a book is these 3 numbers.If you have a roommate, and she's using the same technique, she can take the book while you're not using it, and resume reading from where she stopped.Then you can take it back, and resume it from where you were.

Threads work in the same way.

  A CPU is giving you the illusion that it's doing multiple computations at the same time.It does that by spending a bit of time on each computation.It can do that because it has an execution context for each computation.Just like you can share a book with your friend, many tasks can share a CPU.On a more technical level, an execution context (therefore a thread) consists of the values of the CPU's registers.

  Last: threads are different from processes.

  A thread is a context of execution, while a process is a bunch of resources associated with a computation.

  A process can have one or many threads.

  Clarification: the resources associated with a process include memory pages (all the threads in a process have the same view of the memory), file descriptors (e.g., open sockets), and security credentials (e.g., the ID of the user who started the process).

  上面这段话的意思是:

  一个线程是一个可执行的上下文,这个上下文就是CPU在执行一个指令流时需要的所有信息。假设你正在读一本书,而且你现在想暂停一下,但是你想过一会儿会来从你停下的地方继续阅读这本书。一种方法就是你记下来停止时的页码,行号以及第几个字。所以,你可以使用这三个数字的上下文来执行读书这件事。如果你有一个室友,她也使用这样的方法,那么她就能在你不读这本书的时候来读,而且还可以从她上次中断的地方继续读。然后,你可以把书拿回来,从上次中断的地方继续。

  线程就是这么执行的。

  CPU给人一种幻觉,那就是它在同一时间同时执行了多个任务。CPU通过给每个任务一点运行时间来实现这一点。CPU可以完成这一点就是因为它给每个计算任务都记录并执行了上下文。就像你可以和你的朋友共享一本书一样,多任务可以共享一个CPU。在深层次的技术层面,一个可执行的上下文(就是一个线程)由CPU寄存器中的值组成。

  最后,线程和进程是不一样的。

  一个线程是一个可执行的上下文,一个进程是一组计算资源的集合。

  一个进程可以有一个或多个线程。

  声明:与进程相关的资源包括内存页(同一个进程中的所有线程共享内存),文件描述符和安全认证

  2、什么是进程 

  An executing instance of a program is called a process.

  Each process provides the resources needed to execute a program. A process has a virtual address space, executable code, open handles to system objects, a security context, a unique process identifier, environment variables, a priority class, minimum and maximum working set sizes, and at least one thread of execution. Each process is started with a single thread, often called the primary thread, but can create additional threads from any of its threads.

  一个程序的可执行实例称为一个进程。

  每个进程提供了程序运行所需的资源。一个进程拥有一个虚拟地址空间,可执行代码,打开操作系统对象的句柄,一个安全上下文,一个唯一的进程标识符,环境变量,优先级,最大和最小的运行空间和至少一个可执行线程。每个进程从一个线程开始,通常称为主线程,但是可以从其任何一个线程来创建新线程。

  3、线程和进程的区别

    1)、Threads share the address space of the process that created it; processes have their own address space.

    2)、Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.

    3)、Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.

    4)、New threads are easily created; new processes require duplication of the parent process.

    5)、Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.

    6)、Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.

    1)、线程共享其所属进程的地址空间;进程拥有各自独立的地址空间

    2)、线程可以直接访问进程的数据段;进程从其父进程拷贝一份数据

    3)、同一个进程中的所有线程之间可以直接通信;进程必须通过第三方中间件来进行通信

    4)、新线程很容易创建;新进程需要从父进程进行复制

    5)、线程可以很容易控制同一进程中的其他线程;进程只能控制其子进程

    6)、对于主线程的修改,有可能会影响到同一进程中其他线程的运行;改变父进程的修改,不会影响其他子进程

  4、写一个多线程的程序

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import threading,time

def run(n):
    print("running threading: ",n)
    time.sleep(2)


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

运行结果:
running threading:  0
running threading:  1
running threading:  2
running threading:  3
running threading:  5
running threading:  4
running threading:  6
running threading:  7
running threading:  8
running threading:  9

  从上述代码中我们可以看到,创建多线程需要使用threading这个模块,创建多线程的基本步骤如下:

    1)、导入threading模块

    2)、定义多线程要执行的任务

    3)、创建线程实例:t = threading.Thread(target="函数名",args=(参数1,参数2,...))

    4)、启动线程:t.start()

  5、join()

  上述代码中我们看到,所有线程基本是在同时执行的,那如果我们想看看所有线程执行完成所用的时间的话如何实现呢?先看代码:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import threading,time

def run(n):
    print("running threading: ",n)
    time.sleep(2)
    print("threading %s done" % n)

time_start = time.time()
for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()

print("----------------------------------")
print("cost:" ,(time.time() - time_start))


运行结果:
running threading:  0
running threading:  1
running threading:  2
running threading:  3
running threading:  4
running threading:  5
running threading:  6
running threading:  7
running threading:  8
running threading:  9
----------------------------------
cost: 0.0018157958984375
threading 1 done
threading 4 done
threading 2 done
threading 9 done
threading 3 done
threading 6 done
threading 5 done
threading 0 done
threading 7 done
threading 8 done

  WTF?!这样的结果是为什么?我们从运行结果上可以看到,线程启动完成后,我们的程序并没有等待线程执行结束就继续向下执行了,这是因为我们程序的主线程并不会等待子线程执行完毕就会继续向下执行导致的,如果需要让主线程等待子线程执行完毕,那就需要用到一个方法:join()方法:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import threading,time

def run(n):
    print("running threading: ",n)
    time.sleep(2)
    print("threading %s done" % n)

t = threading.Thread(target=run,args=(1,))
t.start()
t.join()

print("----------------------------------")

运行结果:
running threading:  1
threading 1 done
----------------------------------

  从上述代码中我们可以看到,主线程的确在等待子线程结束完成后才继续执行,那么是多线程呢?如何让主线程等待子线程呢?答案是,我们将所有的线程实例都放入一个列表,线程启动后再去循环这些列表就可以了:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import threading,time

def run(n):
    print("running threading: ",n)
    time.sleep(2)
    print("threading %s done" % n)

time_start = time.time()
t_list = []
for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()
    t_list.append(t)

for j in t_list:
    j.join()

print("----------------------------------")
print("cost:" ,(time.time() - time_start))

运行结果:
running threading:  0
running threading:  1
running threading:  2
running threading:  3
running threading:  4
running threading:  5
running threading:  6
running threading:  7
running threading:  8
running threading:  9
threading 0 done
threading 5 done
threading 8 done
threading 4 done
threading 1 done
threading 2 done
threading 3 done
threading 6 done
threading 7 done
threading 9 done
----------------------------------
cost: 2.003788948059082

   6、守护线程

  在上述代码中,我们使用join()让主线程等待所有子线程执行完毕后再继续执行,如果不适用join()方法的话,主线程就会和子线程一起并发的执行,而且可以看到,主线程执行完毕后程序并没有直接退出,而是等待所有子线程都执行完毕后程序才退出,那么问题就来了,如果在一个程序中,一个子线程负责监听一个端口,那如果这个程序挂了,但是子线程却没有退出,就会导致这个端口被占用,那有没有一个方法,可以在程序退出的时候不论子线程执行完毕与否,都自动结束子线程呢?答案是有的,那就是守护线程:

  将一个线程设置为守护线程后,那这个线程所在的主线程在退出后,该子线程就会立即退出。

  来我们看代码:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import threading,time

def run(i):
    print("start task:" , i)
    time.sleep(2)
    print("task %s done" % i)

for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.setDaemon(True)
    t.start()


print("----------------Main thread is done----------------")

运行结果:
start task: 0
start task: 1
start task: 2
start task: 3
start task: 4
start task: 5
start task: 6
start task: 7
start task: 8
start task: 9
----------------Main thread is done----------------

  从上述代码可以看到,在启动线程前,使用setDaemon(True)方法就可以把这个线程设置为守护线程,主线程执行完毕后并没有等待子线程执行完毕,程序就立即退出了,这就是守护线程,这样的好处在于程序退出时,可以强制释放掉一些占用的系统资源,防止其变成僵尸线程。

  7、GIL全局解释器锁

  先来看多线程运行的两个概念:并发和并行

  并发:当有多个线程在操作时,如果系统只有一个CPU(单核),则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状态。这种方式我们称之为并发(Concurrent)。

  并行:当系统有一个以上CPU(或CPU有多核)时,则线程的操作有可能非并发。当一个CPU(或一个核)执行一个线程时,另一个CPU(或一个核)可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

  并发和并行的区别就是一个处理器同时处理多个任务和多个处理器或者是多核的处理器同时处理多个不同的任务。前者是逻辑上的同时发生,而后者是物理上的同时发生。

  python由于其设计之初的局限性,不借助三方库的情况下其多线程的实现采用的是并发的方式,而非并行的方式,这就意味着python代码在执行时无法完全利用cpu的计算资源,只可以在单个CPU上的单个核心中通过并发的方式执行,这也是python被人诟病最多的一点,说python的多线程是假的多线程。关于这点,网上有很多讨论的文章,可以搜索来看下,这里不再赘述。

  首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把 GIL 归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL 。

  那么CPython实现中的GIL又是什么呢?GIL全称 Global Interpreter Lock 为了避免误导,我们还是来看一下官方给出的解释:

  In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

  在CPython中,GIL是一个互斥锁,用于阻止多个线程同一时间执行python代码。这个锁是有必要的,因为CPython的内存管理机制不是线程安全的。(然而,由于有GIL存在,其他特性的开发已经都依赖于它了。)

  为什么会存在GIL这个锁呢?GIL就是为了保证在同一时间,只有一个线程在运行,这也就确保了多线程并发执行的特性。

  关于更多的GIL相关知识,可以看这篇文章:http://www.tuicool.com/articles/7zIra2r

  8、互斥锁

  python中虽然使用了GIL,但是在多线程中如果多个线程都要修改同一份数据,那么新的问题就出现了,我们来看代码:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import threading

def run():
    global num
    num += 1

num = 0
t_list = []
for i in range(1000):
    t = threading.Thread(target=run)
    t_list.append(t)
    t.start()

for j in t_list:
    j.join()

print("num: ",num)

python2中运行结果:
zhanghaoyandeMacBook:~ zhanghaoyan$ python thread_lock.py
('num: ', 1000)
zhanghaoyandeMacBook:~ zhanghaoyan$ python thread_lock.py
('num: ', 1000)
zhanghaoyandeMacBook:~ zhanghaoyan$ python thread_lock.py
('num: ', 1000)
zhanghaoyandeMacBook:~ zhanghaoyan$ python thread_lock.py
('num: ', 998)
zhanghaoyandeMacBook:~ zhanghaoyan$ python thread_lock.py
('num: ', 1000)
zhanghaoyandeMacBook:~ zhanghaoyan$ python thread_lock.py
('num: ', 1000)

  注意上述代码执行结果中看到,有一次的执行结果是错误的,为什么会出现这个结果呢?不是已经有GIL了吗?这就是上面说过的多线程同时修改同一份数据的问题:

    当线程1拿到初始数据,在修改该数据完成之前其CPU时间到期,导致其释放GIL,线程被挂起。

    线程2被激活,同样拿到了还未被线程1修改的初始数据,但线程2在CPU时间到期之前就完成了修改数据的操作,此时,初始数据已经被修改。

    线程1再次被激活时,不会重新拿取要修改的数据,而是根据上下文中的记录去继续未完成的操作,这时线程1再去修改初始数据,就会把线程2修改完的数据给覆盖掉,从而导致数据错误。

  也正是由于上述过程的存在,才会导致多线程中修改同一份数据时可能出现数据异常的情况,那如何避免这种情况的发生呢,那就是通过加锁来确保同一份数据只有一个线程能修改,来看代码:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
__Author__ = "ZHY"

import threading

def run():
    lock.acquire()  #加锁
    global num
    num += 1
    lock.release()  #释放锁

lock = threading.Lock() #生成锁实例
num = 0
t_list = []
for i in range(1000):
    t = threading.Thread(target=run)
    t_list.append(t)
    t.start()

for j in t_list:
    j.join()

print("num: ",num)

  从上述代码中可以看到,我们在修改数据之前,先申请了一把锁,在修改数据完成之后,再释放这把锁,这样,就可以保证同一份数据同时只能有一个线程来修改,也就保证了数据的正确性。

   9、递归锁

  当一把锁中还有同样的另一把锁的时候,如果不使用递归锁,则会导致死锁现象,递归锁用法如下:初始化锁实例时使用threading.Rlock()方法即可

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import threading,time

def run1():
    lock.acquire()
    print("running run1")
    lock.release()
    return 1

def run2():
    lock.acquire()
    print("running run2")
    lock.release()
    return 2

def run3():
    lock.acquire()
    res1 = run1()
    print("run1 done")
    res2 = run2()
    print("run2 done")
    lock.release()

lock = threading.RLock()
for i in range(10):
    t = threading.Thread(target=run3)
    t.start()

while threading.active_count() != 1:
    print("thread acount:" , threading.active_count())
else:
    print("all thread done")

 

  10、信号量

  我们还可以通过信号量来控制同时执行的最多线程数量,类似于线程池的概念:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import threading,time

def run(n):
    sem.acquire()
    print("run:" , n)
    time.sleep(2)
    sem.release()

sem = threading.BoundedSemaphore(5)
for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()

while threading.active_count() != 1:
    continue
else:
    print("all thread done")

  上述代码运行时可以看到,同时有5个线程进行。使用信号量的步骤与使用锁类似:

    声明信号量:sem = threading.BoundedSemaphore(5)

    线程申请信号量:sem.acquire()

    运行完成后释放信号量:sem.release()

三、事件

  上述多线程在运行的过程中都是独立运行的,如果一个线程执行需要另一个线程的执行结果来执行,也就是说线程之间需要通信,那怎么实现呢?这就需要用到事件的概念了,在一个线程执行中去设置一个事件标志位,另一个进程去判断这个事件标志位是否被设置,根据结果来做出相应的操作。

  使用事件的步骤如下:

  1、初始化事件实例

  2、设置事件标志位/清空事件标志位

  3、判断事件标志位,进行操作

  写一个红绿灯的程序,红绿灯交替5秒,红灯亮时汽车停止通行,绿灯亮时汽车继续通行,来看代码:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import threading,time

event = threading.Event()   #初始化一个事件实例

def light():
    count = 0
    while True:
        if count <= 5:
            event.set() #设置标志位,红灯亮
            print("\033[41;1mRed light working!\033[0m",5-count)
        elif count > 5 and count < 11:
            event.clear()   #清除标志位,绿灯亮
            print("\033[42;1mGreen light working!\033[0m",11-count)
        else:
            count = -1
        count += 1
        time.sleep(1)

def car():
    while True:
        if event.is_set():  #判断标志位是否被设置
            print("The red light working,stop and wait for green!")
        else:
            print("The green light working,keep going!")
        time.sleep(1)


Light = threading.Thread(target=light)
Light.start()

car1 = threading.Thread(target=car)
car1.start()


运行结果:
Red light working! 5
The red light working,stop and wait for green!
Red light working! 4
The red light working,stop and wait for green!
The red light working,stop and wait for green!
Red light working! 3
The red light working,stop and wait for green!
Red light working! 2
The red light working,stop and wait for green!
Red light working! 1
The red light working,stop and wait for green!
Red light working! 0
Green light working! 5
The green light working,keep going!
Green light working! 4
The green light working,keep going!
Green light working! 3
The green light working,keep going!
Green light working! 2
The green light working,keep going!
Green light working! 1
The green light working,keep going!
The green light working,keep going!
Red light working! 5
The red light working,stop and wait for green!
Red light working! 4
The red light working,stop and wait for green!
Red light working! 3
The red light working,stop and wait for green!
The red light working,stop and wait for green!
Red light working! 2
The red light working,stop and wait for green!
Red light working! 1
红绿灯

 

四、队列

  队列就是一个线性表,类似于列表或元组,都是有顺序的数据集合,但是队列和列表等其他数据类型有区别,队列保存在内存中,从队列中取出一个数据后该数据就从队列中删除掉了。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import queue

q = queue.Queue(maxsize=10)

for i in range(10):
    q.put(i)

print("q.qsize():",q.qsize())
print("q.full():",q.full())
print("q.empty():",q.empty())
print(q.get())
print("q.qsize():",q.qsize())
print("q.full():",q.full())
print("q.empty():",q.empty())


运行结果:
q.qsize(): 10
q.full(): True
q.empty(): False
0
q.qsize(): 9
q.full(): False
q.empty(): False

  q = queue.Queue(maxsize=xx):声明一个先进先出的队列,maxsize参数用于指定队列大小

  q = queue.LifoQueue(maxsize=xx):声明一个后进先出的队列

  q = queue.PriorityQueue(maxsize=xx):声明一个有优先级的队列

  q.put("data"):向队列中插入数据

  q.get(block=False,timeout=1):从队列中取出数据,当队列中没有数据时,如果没有设置block和timeout参数,则程序会阻塞,block参数设置为False表示取不到数据时不阻塞,timeout表示取不到数据时阻塞的最长超时时间。

  q.get_nowait():从队列中取数据,从不阻塞

  q.qsize():返回队列长度

  q.empty():如果队列为空,则返回True,否则返回False

  q.full():如果队列满了,返回True,否则返回False

五、生产者消费者模型

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import threading,time,queue

shop = queue.Queue(maxsize=10)

def Produce(product):
    i = 0
    while True:
        print("produce product:" , product,i)
        shop.put("%s [%s]" %(product,i))
        i += 1
        time.sleep(0.1)

def Consumer(name):
    while True:
        print("%s get bone:%s" %(name,shop.get(timeout=1)))
        time.sleep(1)

produce1 = threading.Thread(target=Produce,args=("Bone",))
produce1.start()

consumer1 = threading.Thread(target=Consumer,args=("zhangsan",))
consumer1.start()


运行结果:
produce product: Bone 0
zhangsan get bone:Bone [0]
produce product: Bone 1
produce product: Bone 2
produce product: Bone 3
produce product: Bone 4
produce product: Bone 5
produce product: Bone 6
produce product: Bone 7
produce product: Bone 8
produce product: Bone 9
zhangsan get bone:Bone [1]
produce product: Bone 10
produce product: Bone 11
produce product: Bone 12
zhangsan get bone:Bone [2]
……

 

posted @ 2016-10-10 17:04  没有手艺的手艺人  阅读(1341)  评论(0编辑  收藏  举报