python之线程、套接子

1.线程
概述:
线程是操作系统能够进行运算调度的最小单位(程序执行流的最小单元),它被包括在进程之中,是进程的实际运作单位.
一个进程可以并发多个线程,每条线程并行执行不同的任务(线程是进程的一个实体,是被系统独立调度和分派的基本单元)
每一个进程启动时都会最先产生一个线程,即主线程. 然后主线程会再创建其他的子线程


代码1


from threading import Thread
# 定义函数
def Fuc(a):
    print a
# 打印 before 和 after 为主线程
print 'before'
# 线程和函数建立关系
# t1为子线程
t1 = Thread(target=Fuc,args=(3,))
t1.start()
print t1.getName()
print 'after'

执行结果:
python之线程、套接子


代码2


from threading import Thread
# 定义函数
def Fuc(a):
    print a
# 打印 before 和 after 为主线程
print 'before'
# 线程和函数建立关系
# t1为第一个子线程
t1 = Thread(target=Fuc,args=(1,))
t1.start()
print t1.getName()
# t2为第二个子线程
t2 = Thread(target=Fuc,args=(2,))
t2.start()
print t2.getName()
print 'after'


执行结果:
python之线程、套接子


代码3:


"""主线程不等待子线程"""
from threading import Thread
import time
def Fuc():
    # rang(10)表示i的数据变化范围为0-9
    for i in range(10):
        print i
        # 每输出一个i的值中间休眠1秒 以便于观察现象
        time.sleep(1)
print 'before'
t1 = Thread(target=Fuc)
t1.start()
print 'after'

# 注意:子线程与主线程同步执行,但主线程不会等待子线程


执行结果:
python之线程、套接子


代码4:


"""主线程不等待子线程 但会等到子线程结束之后一起销毁 """
from threading import Thread
import time
def Fuc():
    for i in range(10):
        print i
        time.sleep(1)
print 'before'
t1 = Thread(target=Fuc)
# 等待子线程结束之后一起销毁
t1.setDaemon(True)
t1.start()
print 'after'
time.sleep(10)

执行结果:
python之线程、套接子

 

代码5:


"""主线程等待子线程"""
from threading import Thread
import time
def Fuc():
    for i in range(10):
        print i
        time.sleep(1)
print 'before'
t1 = Thread(target=Fuc)
t1.start()
# t1.join()表示主线程等待子线程执行完才结束
# t1.join(5)表示主线程主会等待子线程5秒之后就结束,不管子线程是否完成
t1.join(5)
print 'after'

执行结果:
python之线程、套接子


实例

需求:
模拟听歌和看电影,一般不会同时进行
但从执行效率来讲,只有在听完音乐之后才会进行看电影,这样效率太低

代码1:


from time import ctime, sleep
def music(a):
    for i in range(2):
        print 'I was listening to %s. %s' % (a, ctime())
        # 每打印一次中间休眠2秒
        sleep(2)
def movie(b):
    for i in range(3):
        print 'I was listening to %s. %s' % (b, ctime())
        sleep(5)
music('可能否')
movie('捉妖记')
print 'all over %s' % ctime()


执行结果:
python之线程、套接子

 

需求:(改进:引入子进程)
模拟听歌和看电影,虽然一般不同时进行
但实际上来看二者是可以同时进行的,比如扣扣与微信可以同时的登陆并且二者互不干扰

代码2:


from threading import Thread
from time import ctime, sleep
def music(a):
    for i in range(2):
        print 'I was listening to %s. %s' % (a, ctime())
        sleep(2)
def movie(b):
    for i in range(2):
        print 'I was listening to %s. %s' % (b, ctime())
        sleep(5)
# 两个子进程同时进行并且互不干扰
t1 = Thread(target=music, args=('可能否',))
t1.start()
t2 = Thread(target=movie, args=('捉妖记',))
t2.start()
# ctime() 表示执行时间
print 'all over %s' % ctime()


执行结果:
python之线程、套接子

 

2.多线程

生产者消费者问题:(经典)
一直生产 一直消费 中间有阀值 避免供求关系不平衡.线程安全问题,要是线程同时来,听谁的
锁:一种数据结构 队列:先进线出 栈:先进后出

生产者消费者的优点(为什么经典的设计模式)
    1.解耦(让程序各模块之间的关联性降到最低)
    假设生产者和消费者是两个类,如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合),
 如果将来消费者的代码发生变换,可能会影响到生产者,而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了
举个例子,我们去邮局投递信件,如果不使用邮筒(也就是缓冲区),你必须得把信直接交给邮递员,有同学会说,直接交给邮递员不是挺简单的嘛,其实不简单,你必须得认识邮递员,才能把信给他(光凭身上的制服,万一有人假冒呢???),这就产成你和邮递员之间的依赖了(相当于生产者消费者强耦合),万一哪天邮递员换人了,你还要重新认识一下(相当于消费者变化导致修改生产者代码),而邮筒相对来说比较固定,你依赖它的成本就比较低(相当于和缓冲区之间的弱耦合)
    2.支持并发
    生产者消费者是两个独立的并发体,他们之间是用缓冲区作为桥梁连接,生产者之需要往缓冲区里丢数据,就可以继续生产下一个数据,而消费者者只需要从缓冲区里拿数据即可,这样就不会因为彼此速度而发生阻塞,接着上面的例子:如果我们不使用邮筒,我们就得在邮局等邮递员,直到他回来了,我们才能把信给他,这期间我们啥也不能干(也就是产生阻塞),或者邮递员挨家挨户的问(产生论寻)
   3.支持忙闲不均
      如果制造数据的速度时快时慢,缓冲区的好处就体现出来了,当数据制造快的时候, 消费者来不及处理,未处理的数据可以暂时存在缓冲区中,等生产者的速度慢下来,消费者再慢慢处理, 情人节信件太多了,邮递员一次处理不了,可以放在邮筒中,下次在来取


队列:先进先出 忙闲不均


实例:

模拟厨师做包子,消费者吃包子

代码1:


"""没有交互也不是动态的"""
import threading
import Queue
import time
def Producer(name, que):
    que.put('baozi')
    print '%s:Made a baozi...' % name
def Consumer(name,que):
    que.get()
    print '%s:Got a baozi...' % name
# 创建队列
q = Queue.Queue()
p1 = threading.Thread(target=Producer, args=['chef1', q])
p2 = threading.Thread(target=Producer, args=['chef2', q])
p1.start()
p2.start()
c1 = threading.Thread(target=Consumer, args=['tom', q])
c2 = threading.Thread(target=Consumer, args=['harry', q])
c1.start()
c2.start()

执行结果:

python之线程、套接子

 

代码2:


"""添加while循环使其改进为动态"""
import threading
import Queue
import time
import random


def Producer(name, que):
    # 动态过程
    while True:
        que.put('baozi')
        print '%s:Made a baozi...' % name
        time.sleep (random.randrange(3))


def Consumer(name, que):
    while True:
        que.get()
        print '%s:Got a baozi...' % name
        time.sleep(random.randrange(3))
# 创建队列
q = Queue.Queue()
p1 = threading.Thread(target=Producer, args=['chef1', q])
p2 = threading.Thread(target=Producer, args=['chef2', q])
p1.start()
p2.start()
c1 = threading.Thread(target=Consumer, args=['tom', q])
c2 = threading.Thread(target=Consumer, args=['harry', q])
c1.start()
c2.start()

执行结果:
python之线程、套接子


代码3:


"""动态过程,消费者不等待,即如果吃包子比做包子慢便会报错"""
import threading
import Queue
import time
import random


def Producer(name, que):
    while True:
        que.put('baozi')
        print '%s:Made a baozi...' % name
        time.sleep (random.randrange(3))


def Consumer(name, que):
    while True:
        # 消费者不等待
        que.get_nowait()
        print '%s:Got a baozi...' % name
        time.sleep(random.randrange(3))
# 创建队列
q = Queue.Queue()
p1 = threading.Thread(target=Producer, args=['chef1', q])
p2 = threading.Thread(target=Producer, args=['chef2', q])
p1.start()
p2.start()
c1 = threading.Thread(target=Consumer, args=['tom', q])
c2 = threading.Thread(target=Consumer, args=['harry', q])
c1.start()
c2.start()

执行结果:
python之线程、套接子


代码4:


"""动态过程,交互式;若吃包子比做包子慢便会报错,此时用try来捕获异常"""
import threading
import Queue
import time
import random


def Producer(name, que):
    while True:
        que.put('baozi')
        print '%s:Made a baozi...' % name
        time.sleep (random.randrange(5))


def Consumer(name, que):
    while True:
        # 捕获异常
        try:
            que.get_nowait()
            print '%s:Got a baozi...' % name
        except Exception:
            print '没有包子了'
        time.sleep(random.randrange(3))
# 创建队列
q = Queue.Queue()
p1 = threading.Thread(target=Producer, args=['chef1', q])
p2 = threading.Thread(target=Producer, args=['chef2', q])
p1.start()
p2.start()
c1 = threading.Thread(target=Consumer, args=['tom', q])
c2 = threading.Thread(target=Consumer, args=['harry', q])
c1.start()
c2.start()


执行结果:
python之线程、套接子


(1).事件驱动
代码:


import threading
import time

def Producer():
    print 'chef:等人来买包子'
    #收到了消费者的event.set 也就是把这个flag改为了true,但是我们的包子并没有做好
    event.wait()
    #此时应该将flag的值改回去
    event.clear()
    print 'chef:someone is coming for 包子'
    print 'chef:making a 包子 for someone'
    time.sleep(5)
    # 告诉人家包子做好了
    print '你的包子好了~'
    event.set()

def Consumer():
    print 'tom:去买包子'
    # 告诉人家我来了
    event.set()
    time.sleep(2)
    print 'tom:waiting for 包子 to be ready'
    event.wait()
    print '哎呀~真好吃'

event = threading.Event()

p1 = threading.Thread(target=Producer)
c1 = threading.Thread(target=Consumer)
p1.start()
c1.start()

执行结果:
python之线程、套接子

 

(2).异步
代码:


import threading
import time

def Producer():
    print 'chef:等人来买包子'
    # 收到了消费者的event.set 也就是把这个flag改为了true,但是我们的包子并没有做好
    event.wait()
    # 此时应该将flag的值改回去
    event.clear()
    print 'chef:someone is coming for 包子'
    print 'chef:making a 包子 for someone'
    time.sleep(5)
    print '你的包子好了~'
    event.set()

def Consumer():
    print 'tom:去买包子'
    event.set()
    time.sleep(2)
    print 'tom:waiting for 包子 to be ready'
    # 我在不断检测,但我已经不阻塞了
    while True:
        if event.is_set():
            print 'Thanks~'
            break
        else:
            print '怎么还没好呀~'
            time.sleep(1)
event = threading.Event()
# 创建两个子进程并与两个函数相联系
p1 = threading.Thread(target=Producer)
c1 = threading.Thread(target=Consumer)
p1.start()
c1.start()

执行代码:

python之线程、套接子


(3)线程安全问题
代码1:


"""线程会出现异常无法输出正确的结果且格式凌乱"""
import threading
import time
num = 0


def run(n):
    time.sleep(1)
    global num
    num += 1
    print '%s\n' % num

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

执行结果:
python之线程、套接子

代码2:


"""给线程加锁可以使得输出结果正确且输出规范"""
import threading
import time
num = 0


def run(n):
    time.sleep(1)
    global num
    lock.acquire()
    num += 1
    print '%s\n' % num
    lock.release()
lock = threading.Lock()
for i in range(1500):
    t = threading.Thread(target=run,args=(i,))
    t.start()

执行结果:

python之线程、套接子


3.socket套接子
概述:
  网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket,所谓socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过“套接字”向网络发出请求或应答网络请求,socket起源于Uinx,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open-->读写write/read-->关闭close”模式来操作,socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写 IO,打开,关闭),Socket的英文原义是“孔”或“插座”.作为BSD UNIX的进程通信机制,取后一种意思.通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务.Socket正如其英文原义那样,像一个多插孔座.一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目. 客户软件将插头插到不同编号的插座,就可以得到不同的服务.

例如:中国移动客服
对于移动来说:一直监听一个号码10086,当有电话进来后,就分配一个客服和客户去沟通并处理请求
对于用户:需要知道10086这个号码,并需要打电话


让服务端一直运行,在终端调用python client.py
在终端操作:


[[email protected] ~]$ cd /home/kiosk/
[[email protected] ~]$ ls
Desktop    java_error_in_PYCHARM_2585.log  Pictures         python07
Documents  Music                           Public           Templates
Downloads  oop.exam                        PycharmProjects  Videos
[[email protected] ~]$ cd PycharmProjects/
[[email protected] PycharmProjects]$ ls
python04  pythonday07  pythonday08
[[email protected] PycharmProjects]$ cd pythonday08
[[email protected] pythonday08]$ ls
mysql  socket套接子  多线程
[[email protected] pythonday08]$ cd socket套接子
[[email protected] socket套接子]$ ls
1-server服务端.py  2-client客户端.py  3-server.py  4-client.py
[[email protected] socket套接子]$ python 2-client.py
hello
"""

(1).server服务端
代码:


import socket

# 创建一个socket对象
client = socket.socket()

# 创建连接
ip_port = ('127.0.0.1',9990)
client.connect(ip_port)
while True:
    # 获取数据
    data = client.recv(1024)
    print data

2.client客户端
代码:
import socket

# 创建一个socket对象
client = socket.socket()

# 创建连接
ip_port = ('127.0.0.1',9999)
client.connect(ip_port)
while True:
    # 获取数据
    data = client.recv(1024)
    print data

 

(3).server服务端
在终端操作:


[[email protected] socket套接字]$ ls
1-server服务端.py  2-client客户端.py  3-server.py  4-client.py
[[email protected] socket套接子]$ python 3-server.py
hello
client:nihao
hi
client:exit
"""

代码:


import socket

# 1.创建socket对象
sk = socket.socket()
# 2.绑定端口和ip
ip_port = ('127.0.0.1', 9998)
sk.bind(ip_port)
# 3.最大连接数
sk.listen(5)

while True:
    # 获取客户端的ip和端口号
    conn, address = sk.accept()
    conn.send('hello')
    flag = True
    while flag:
        data = conn.recv(1024)
        print data
        if data == 'exit':
            flag = False
        conn.send('hi')
    conn.close()

 

(4).client客户端
代码:


import socket

# 创建一个socket对象
client = socket.socket()

# 创建连接
ip_port = ('127.0.0.1',9998)
client.connect(ip_port)

while True:
    # 获取数据
    data = client.recv(1024)
    print data
    # 发送数据
    inp = raw_input('client:')
    client.send(inp)
    if inp == 'exit':
        break