Python学习笔记九(UDP套接字和并发编程)

一、UDP套接字

服务端

from socket import *
server = socket(AF_INET,SOCK_DGRAM)
server.bind(("127.0.0.1",8080))
while True:
    data,client_addr = server.recvfrom(1024)
    server.sendto(data.upper(),client_addr)

客户端

from socket import *
client = socket(AF_INET,SOCK_DGRAM)
while True:
    msg = input(">>").strip()
    client.sendto(msg.encode("utf-8"),("127.0.0.1",8080))
    data,server_addr = client.recvfrom(1024)
    print(data.decode("utf-8"))

二、进程相关定义

进程是指程序的运行过程。每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。

多道技术:内存中同时存入多个程序,cpu从一个进程快速切换到另一个,使得每个进程各自运行几十或几百毫秒,虽然在一个时刻,一个cpu只执行了一个任务,但1秒内,cpu却可以运行多个进程,给人带来并行的错觉,即伪并发,以此来区分多处理器操作系统的真正硬件并行(多cpu共享一个内存)

进程三种状态间的转换:

三、python多进程编程

为了利用多核CPU资源,python中使用multiprocessing多线程模块,python多线程无法利用多核优势。进程之间无任何共享数据,进程修改数据仅限进程内。

Process类常用方法:
p.start()   启动进程,调用紫禁城的p.run()方法
p.run()    进程启动时运行的方法,调用target制定的函数,自定义类中必须实现该方法。
p.terminate()  强调终止进程p,不会进行任何清理操作,如果p创建了子进程,该进程就成为了僵尸进程。如果p还保存了一个锁,那么锁也不会释放,导致死锁。
p.is_alive()  如果p仍然运行,返回True
p.join([timeout]) 主线程等待p进程终止。timeout为可选超时时间。
Process类常用属性
p.daemon 默认为False,设置为True后,p代表后台运行的守护进程,当p的父进程终止时,p也随之终止。设定为True后,p不能创建子进程,且必须在p.start()前设置。
p.name 进程名
p.pid    进程pid
p.exitcode  进程在运行时为None,如果为-N,表示被信号N结束
p.authkey  进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功

创建子进程的两种方式

from multiprocessing import Process
import time
def task(name):
    print("%s is running"%name)
    time.sleep(3)
    print("%s is done"%name)
if __name__=="__main__":
    p = Process(target=task,args=("aaa",))
    p.start()
    print("main")
from multiprocessing import Process
import time

class MyProcess(Process):
    def __init__(self,name):
        super(MyProcess,self).__init__()
        self.name = name
    def run(self):
        print("%s is running"%self.name)
        time.sleep(3)
        print("%s is done"%self.name)
if __name__=="__main__":
    p=MyProcess("进程1")
    p.start()
    print("main")

使用join方法等待子进程结束

from multiprocessing import Process
import time
def task(name):
    print("%s is running"%name)
    time.sleep(3)
    print("%s is done"%name)
if __name__=="__main__":
    p = Process(target=task,args=("aaa",))
    p.start()
    p.join()
    print("main")

守护进程

from multiprocessing import Process
import time
def task(name):
    # p = Process(target=time.sleep,args=(1,))  #守护进程无法创建子进程,会报错。
    # p.start()
    print("%s is running"%name)
    time.sleep(3)
    print("%s is done"%name)
if __name__ == "__main__":
    p = Process(target=task,args=("xxx",))
    p.daemon=True
    p.start()
    time.sleep(1)
    print("main")   #主进程在此结束,守护进程也会结束。
from multiprocessing import Process
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")
def bar():
    print(456)
    time.sleep(3)
    print("end456")
if __name__=="__main__":
    p1=Process(target=foo)
    p2=Process(target=bar)
    p1.daemon=True
    p1.start()
    p2.start()
    print("main")   #主进程执行完后,p1守护进程还输入123就已经结束,不过在p2会执行完后,主进程才会结束

互斥锁,针对进程间需要共同操作的资源,需要添加互斥锁

#模拟抢票程序
from multiprocessing import Process,Lock
import json
import time
import random
import os
def search():
    time.sleep(random.randint(1,3))
    dic = json.load(open("db.txt",‘r‘,encoding="utf-8"))
    print("%s查看剩余票数为%s"%(os.getpid(),dic["count"]))
def get():
    dic=json.load(open("db.txt",‘r‘,encoding="utf-8"))
    if dic["count"]>0:
        dic["count"]-=1
        time.sleep(random.randint(1,3))
        json.dump(dic,open("db.txt",‘w‘,encoding="utf-8"))
        print("%s购票成功"%os.getpid())
def task(mutex):
    search()
    mutex.acquire()
    get()     #对操作余票的函数加锁
    mutex.release()
if __name__=="__main__":
    mutex = Lock()
    for i in range(10):
        p=Process(target=task,args=(mutex,)) #进程间数据不互通,需用参数传入锁
        p.start()

使用Queue实现生产者消费者模型,Queue自带锁。

from multiprocessing import Process,Queue
import time
import random

def producer(name,food,q):
    for i in range(10):
        res="%s%s"%(food,i)
        time.sleep(random.randint(1,3))
        q.put(res)
        print("厨师[%s]生产了[%s]"%(name,res))
def consumer(name,q):
    while True:
        res = q.get()
        time.sleep(random.randint(1,3))
        print("吃货[%s]吃了[%s]"%(name,res))
if __name__=="__main__":
    q=Queue()
    p1 = Process(target=producer,args=("厨师1","包子",q))
    c1 = Process(target=consumer,args=("猪1",q))
    p1.start()
    c1.start()
    print("main")

上面的程序中生产者做完产品后,消费者并不知道已经生产完了,仍在在等着消费,主进程阻塞无法结束。

通过使用JoinableQueue队列可解决以上问题。

from multiprocessing import Process,JoinableQueue
import time
import random

def producer(name,food,q):
    for i in range(10):
        res="%s%s"%(food,i)
        time.sleep(random.randint(1,3))
        q.put(res)
        print("厨师[%s]生产了[%s]"%(name,res))
def consumer(name,q):
    while True:
        res = q.get()
        time.sleep(random.randint(1,3))
        print("吃货[%s]吃了[%s]"%(name,res))
        q.task_done()
if __name__=="__main__":
    q=JoinableQueue()
    p1 = Process(target=producer,args=("厨师1","包子",q))
    c1 = Process(target=consumer,args=("猪1",q))
    c1.daemon=True     #c1中有死循环,需要设置为守护进程,主进程结束自动结束消费者。
    p1.start()
    c1.start()
    p1.join()
    q.join()
    print("main")

四.线程介绍

1.线程相关定义

线程与进程类似,不过是在同一进程下执行的,并且共享一片数据空间。进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。

使用多线程的原因:

a)多线程共享一个进程的地址空间

b)线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程快10-100倍,再有大量线程需要动态和快速修改时,较有用。

c)若多线程是cpu密集型,那么并不能获得性能上的增强,但如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而加快程序执行的速度。

2.创建线程

python中使用threading模块创建线程,和multiprocess模块类似。

#第一种方式
from threading import Thread
import time
import random

def task(name):
    print("%s is running"%name)
    time.sleep(random.randint(1,3))
    print("%s is done"%name)
if __name__=="__main__":
    t1 = Thread(target=task,args=("xxx",))
    t1.start()
    print("main")  #先输出线程中的内容
#第二种方式
from threading import Thread
import time
import random
class MyThread(Thread):
    def __init__(self,name):
        super(MyThread,self).__init__()
        self.name = name
    def run(self):
        print("%s is running"%self.name)
        time.sleep(random.randint(1,3))
        print("%s is done"%self.name)
if __name__=="__main__":
    t1 = MyThread("xxx")
    t1.start()
    print("main")  #先输出线程中的内容

3.GIL

尽管python解释器中可以运行多个线程,但在任意给定时刻只有一个线程会被解释器执行。GIL本质为一个互斥锁,将并发运行变成串行。

对于任意面向I/O的Python功能,GIL会在I/O调用前被释放,以允许其他线程在I/O执行的时候运行。而对于没有太多I/O操作的代码,更倾向于在该线程整个时间片内始终占用处理器和GIL。

I/O密集型Python程序比计算密集型代码能够更好地利用多线程环境。

计算密集型程序,多进程效率高,主要用于金融分析。

from multiprocessing import Process
from threading import Thread
import os,time
def work():
    res=0
    for i in range(100000000):
        res*=i
if __name__=="__main__":
    l=[]
    print(os.cpu_count())   #8核
    start=time.time()
    for i in range(4):
        # p = Process(target=work)    #多进程为6.448570728302002秒
        p = Thread(target=work)   #多线程为21.265116930007935秒
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop = time.time()
    print("run time is %s"%(stop-start))

I/O密集型程序,多线程效率高,主要用于socket、爬虫、web等。

from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
    time.sleep(2)
    print("==>")
if __name__=="__main__":
    l=[]
    print(os.cpu_count())
    start=time.time()
    for i in range(400):
        # p = Process(target=work)  #多进程9.083257913589478秒
        p = Thread(target=work)     #多线程2.039461612701416秒
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop = time.time()
    print("run time is %s"%(stop-start))

原文地址:https://www.cnblogs.com/n1ghtwatcher/p/8414591.html

时间: 2024-09-30 11:20:01

Python学习笔记九(UDP套接字和并发编程)的相关文章

python学习笔记九——文件与目录

1.python进行文件读写的函数是open或file类 mode:r  只读 r+   读写 w  写入,先删除原文件,再重新写入,如果文件没有则创建 w+  读写,先删除原文件,再重新写入,如果文件没有则创建(可写入和输出) a  写入,在文件末尾追加新的内容,文件不存在则创建 a+  读写,在文件末尾追加新的内容,文件不存在则创建 b  打开二进制文件,可与r,w,a,+结合使用 U  支持所有的换行符号,"\r","\n","\r\n"

【Python网络编程】利用Python进行TCP、UDP套接字编程

之前实现了Java版本的TCP和UDP套接字编程的例子,于是决定结合Python的学习做一个Python版本的套接字编程实验. 流程如下: 1.一台客户机从其标准输入(键盘)读入一行字符,并通过其套接字将该行发送到服务器. 2.服务器从其连接套接字读取一行字符. 3.服务器将该行字符转换成大写. 4.服务器将修改后的字符串(行)通过连接套接字再发回给客户机. 5.客户机从其套接字中读取修改后的行,然后将该行在其标准输出(监视器)上打印出来. [TCP]服务器端代码: import socket

Java学习笔记(3)----网络套接字服务器多线程版本

本例给出一个客户端程序和一个服务器程序.客户端向服务器发送数据.服务器接收数据,并用它来生成一个结果,然后将这个结果返回给客户端.客户端在控制台上显示结果.在本例中,客户端发送的数据是圆的半径,服务器生成的结果是圆的面积. 客户端通过输出流套接字的 DataOuputStream 发送半径,服务器通过输入流套接字的 DataInputStream 接收半径.服务器计算面积,然后,通过输出流套接字的 DataOutputStream 把它发送给客户端,客户端通过输入流套接字的 DataInputS

TCP/UDP套接字 java socket编程实例

网络协议七层结构: 什么是Socket? socket(套接字)是两个程序之间通过双向信道进行数据交换的端,可以理解为接口.使用socket编程也称为网络编程,socket只是接口并不是网络通信协议. HTTP协议和Socket的区别 http协议是应用层,其模式是请求-应答,客户端发送请求,服务器端进行响应.传输的数据是原始格式的数据,eg :json.xml.text等数据格式. socket不是协议是接口,socket提供TCP/UDP socket 的实例,供java 或者其他语言操作数

python学习笔记(九) - IO编程

一. 文件读写: 1. 读文件: try: f = open('D:\\1.txt', 'r') # 读取普通文件 f = open('D:\\1.jpg', 'rb') # 读取二进制文件 f.read() finally: if f: f.close() with open('D:\\1.txt', 'r') as f: # 使用with会自动调用close for line in f.readlines(): # readlines可以读取一行 print(line.strip()) #

python学习笔记九:正则表达式

本文不涉及正则表达式本身的内容,只记一下python中正则的用法及常用方法. 一.re模块 python中用re模块进行正则处理 >>>import re >>>s = r'abc' >>>re.findall(s,'aaaabcaaaaa') ['abc'] 或先编译(会更快): >>> import re >>> r1 = re.compile(r'abc', re.I) >>> re.find

Python学习笔记九:文件I/O

打印到屏幕: 1 #!/usr/bin/python 2 3 print "Python is really a great language,", "isn't it?"; 读取键盘输入: raw_input input 1 #!/usr/bin/python 2 3 str = raw_input("Enter your input: "); 4 print "Received input is : ", str inpu

Python学习笔记九-文件读写

1,读取文件: f=open('目录','读写模式',encoding='gbk,error='egiong') 后三项可以不写但是默认是' r'读模式:open函数打开的文件对象会自动加上read()方法: f.read()读出刚刚打开的文件:最后一定要记得close()函数:否则会出现不可估计的后果. 读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件.常用模式 .如:'rb','wb','r+b'等等 readline()函数,会依次读取多有文件内容,按行返回lis

python学习笔记(九)-函数2

交换两个变量的值 a = 2 b = 1 b = 1 a = 2 #方式一: b,a = a,b #交换两个变量的值 print(a,b) #方式二: a = a + b #3 b = a - b #2 a = a - b #3-2 #列表推导式 nums = [0,1,3,4,5,6,7] new_nums = [x-1 for x in nums] print(new_nums) return多个值 函数如果有多个return值,那么会把这几个return的值都放到一个元组里面,然后返回 d