网络编程 多线程/socketserver模块/ threading.local

线程:进程中负责程序执行的执行单元。

多线程:在1个进程中存在多个线程。

进程只是用来把资源集中在一起,而线程才是cpu上的执行单位。

每个进程都会默认有一个控制线程也叫作主线程。

进程之间是竞争关系,线程之间是协作关系。

多线程和进程之间的区别?

1.线程开销小,不需要申请内存空间,创建速度快。进程需要申请内存空间,创建速度慢。

2,同一进程下的多个线程,共享该进程的地址空间。

3,改变主进程 ,无法影响子进程,改变了主线程,影响其他线程。原因(该控制线程可以执行代码从而创建新的线程,该主线程的运行周期代表了进程的运行周期)

 

如何开启子线程?有两种方法。

方法一:创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入。(这个方法是重点)

方法二:通过继承Thread类,重写它的run方法;(这个方法作为了解)

方法一:

from threading import Threadimport time ,os

def task():
    print("%s is runing"%os.getpid())
    time.sleep(2)
    print("%s is done"%os.getpid())

if __name__=="__main__":
    t=Thread(target=task)
    t.start()
    print("") #主线程运行周期代表进程的运行周期,他不能先死,他要等子线程运行完和进程意义不同
15640 is runing
主
15640 is runing
 

方法二:

from threading import Thread
import os

class My_task(Thread):
    def __init__(self,name):
        super(My_task,self).__init__()
        self.name=name
    def run(self):
        print("%s is runing" % os.getpid())
        time.sleep(2)
        print("%s is done"%os.getpid())


if __name__ == '__main__':
    t=My_task("小红")
    t.start()
    print(t.name)

结果:

24156 is runing
小红
24156 is done

 子进程不能修改主进程的变量,子线程能修改主线程的变量

范例:

n=1
def t():
    global n
    n=15
if __name__ == '__main__':
        t=Thread(target=t)
        t.start()
        print(n)

结果:

15

线程主要掌握的方法有3个 :

start(),

join()

from threading import current_thread , 中有个叫current_thread .getName()这个可以看线程的名字

线程池:如果你不指定默认是CPU的个数*5,进程池如果你不指定默认是CPU的个数。

from concurrent.futures import ThreadPoolExecutor
from threading import current_thread
import time ,random
def task(n):
    print("%s is running"%current_thread().getName())
    time.sleep(random.randint(1,3))
    return n**2
if __name__ == '__main__':
    t=ThreadPoolExecutor(3)
    objs=[]
    for i in range(10):
        obj=t.submit(task,i)
        objs.append(obj)
    t.shutdown(wait=True)
    for obj in objs:
        print(obj.result())
    print("",current_thread().getName())

结果:

ThreadPoolExecutor-0_0 is running
ThreadPoolExecutor-0_1 is running
ThreadPoolExecutor-0_2 is running
ThreadPoolExecutor-0_1 is running
ThreadPoolExecutor-0_2 is running
ThreadPoolExecutor-0_0 is running
ThreadPoolExecutor-0_2 is running
ThreadPoolExecutor-0_0 is running
ThreadPoolExecutor-0_1 is running
ThreadPoolExecutor-0_0 is running
0
1
4
9
16
25
36
49
64
81
主 MainThread

异步调用:提交完任务(为该任务绑定一个回调函数),不用在原地等任务执行完拿结果,可以直接提交下一个任务。一个任务一旦完成后就会立即触发回调函数的运行。

回调函数的参数是唯一的就是它绑定的返回值。

利用多线程来重写套接字

服务端:

from threading import Thread
import socket
import socketserver

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(("192.168.12.193",8085))
server.listen(5)
print("starting")
def talk(conn,addr):
    """
    接收数据发送数据函数
    :param conn:
    :param addr:
    :return:
    """
    while True:
        try:
            data=conn.recv(1024)
            if not data:break
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
while True:
    conn,addr=server.accept()
    t=Thread(target=talk,args=(conn,addr))
    t.start()

server.close()

客户端:

import socket
custom=socket.socket()
custom.connect(("127.0.0.1",8080))
while True:
    msg=input(">>>>").strip()
    if not msg:
        continue
    custom.send(msg.encode("utf-8"))
    data=custom.recv(1024)
    print(data.decode("utf-8"))
custom.close()

守护进程和守护线程

守护进程:当主进程运行完后,不管子进程运没运行完,子进程都将立即被终止.不管有没有其他的子进程

应用:档主进程执行完了,子进程没必要存在了.

举例子来说明:

不用守护进程的情况下:

from multiprocessing import Process
import os,time

def task():
    time.sleep(2)

    print("这是线程%s"%1)


if __name__ == '__main__':

    t=Process(target=task)

    t.start()
    print('主线程')

结果:

主线程
这是线程1

使用守护进程后:

from multiprocessing import Process
import os,time

def task():
    time.sleep(2)
    print("这是线程%s"%1)

if __name__ == '__main__':
    t=Process(target=task)
    t.daemon=True #注意守护进程必须在p.start()之前设置,开启守护进程不能再开启子进程
    t.start()
    print('主线程')

结果:

主线程

注意:

  1. 注意守护进程必须在p.start()之前设置,
  2. 开启的守护进程不能再开启守护进程的子进程 因为进程之间是相互独立的.如果开启再开启子进程后,当守护进程停止后,没有人回收子进程.
    1.  

守护进程死掉的时间: 当主进程代码执行完后,守护进程就会死掉

守护线程

注意: 

  1. 守护线程必须在p.start()之间设置
  2. 开启的守护线程可以再开启守护进程的子进程,因为在同一个进程中,如果主线程死掉,子线程也会死掉

列如:

from threading import Thread
import os,time

def task():
    time.sleep(2)
    print("这是线程%s"%1)
    tt=Thread(target=time.time()) #开启子线程
    print(time.time())
    tt.start()

if __name__ == '__main__':
    t=Thread(target=task)
    t.daemon=True #守护进程必须在p.start()之前设置,守护进程不能开启子进程
    t.start()
    print('主线程')

结果:

主线程

守护线程死掉的时间:当进程內非守护线程都运行完后他才死掉.这也就是守护线程和守护进程的区别

from threading import Thread
import os,time

def task():
    time.sleep(2)
    print("这是线程%s"%1)

def task1():
    time.sleep(3)
    print("这是线程%s" % 2)
if __name__ == '__main__':
    t1=Thread(target=task)
    t2=Thread(target=task1)
    t1.daemon=True #守护进程必须在p.start()之前设置,守护进程不能开启子进程
    t1.start()
    t2.start()
    print('主线程)

结果:

主线程
这是线程1
这是线程2

 threading.local

我们知道线程之间的数据是共享的,但是有没有一种技术可以让线程内的数据不共享.恰好python 为我们提供了threading.local可以实现该功能.

import threading

local=threading.local()  #实例化一个全局对象
local.val='main-Thread' #在该线程下给local对象添加对象属性

def process_student():
    print('%s (in%s)内存地址为%s'%(local.val,threading.current_thread().getName(),id(local.val)))
def process_thread(name):
    local.val=name
    process_student()

if __name__ == '__main__':
    #开启两个子线程
    t1 = threading.Thread(target=process_thread, args=('one',), name="Thread-A")
    t2 = threading.Thread(target=process_thread, args=('two',), name="Thread-B")
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('主线程的值为%s,内存地址为%s'%(local.val,id(local.val)))#打印当前现成的额值

 

 

结果:

one (inThread-A)内存地址为1545252686736
two (inThread-B)内存地址为1545252717264
主线程的值为main-Thread,内存地址为1545252704688

从结果上看来,两个子线程并没有把local.val中的值覆盖,而是自己重新开辟了一块内存空间,来存放数据,这样就把线程之间的数据給隔离开来了.

作用: 用于保存和隔离线程之间的数据.

应用:

这个东西可以用在那些地方呢,比如下载,现在都是多线程下载了,就像酷狗那样,可以同时下载很多首歌曲,那么

就可以利用这个方法来保存每个下载线程的数据,比如下载进度,下载速度之类的

所以  如果你在开发多线程应用的时候  需要每个线程保存一个单独的数据供当前线程操作,可以考虑使用这个方法,简单有效

 

 

socketserver模块

优秀的博客https://www.cnblogs.com/MnCu8261/p/5546823.html

python共提供了两个socket模块

一个是:socket

另一个是socketserver 模块   简化了网络服务器的开发,解决了io问题。

SocketServer模块简化了编写网络服务程序的任务。同时SocketServer模块也 是Python标准库中很多服务器框架的基础。

这个模块提供了多进程和多线程的接口,但是多进程不能在Windows系统下用

服务端:

import socketserver
class
MyTCPhandler(socketserver.BaseRequestHandler): def handle(self):#重写handle方法 conn=self.request #这步相当于conn addr=self.client_address #这步相当于addr print(conn,addr) while True: try: data=conn.recv(1024) if not data:break conn.send(data.upper()) except ConnectionResetError: break conn.close() if __name__ == '__main__': server=socketserver.ThreadingTCPServer(("127.0.0.1",8080),MyTCPhandler) #这一步就是做了,建立连接,开线程的工作
注意在Windows系统上不能用socketserver来开线程,在其他系统上可以用
socketserver.ForkingTCPServer(("127.0.0.1",8080),MyTCPhandler)来创建
   server.allow_reuse_address=True #是否允许地址的重复利用,默认为false
   server.serve_forever()#一直运行

 

客户端:

import  socket

client=socket.socket()
client.connect(('127.0.0.1',8080))

while True:
    date = input('>>>>')
    client.send(date.encode())
    data = client.recv(1024)
    print('>>>', data.decode())

client.close()

 

转载于:https://www.cnblogs.com/sticker0726/p/7943412.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值