多进程与多线程的理解(TCP服务器案例代码)

1. 进程与线程的关系

进程包含线程,一个进程中包含多个线程.

线程是cpu调度和分配的基本单位,进程是操作系统进行资源分配(cpu,内存,硬盘io等)的最小单位.

2. 多进程解释

多进程可以理解为运行多个同一个版本的程序。相当于并行的多个程序,进行时间的轮询占用CPU资源。如果有2个进程,相当于两个进程并发(不是并行)。有父进程和子进程之分。例如TCP多进程服务器,父程序中监听端口,如果有连接建立,就开一个新的子进程进行对话处理,父进程关闭里面的套接字,新的进程有套接字进行通信,父进程中原来的套接字依旧监听是否有其他的客户端请求。

3. 多线程解释

线程是进程中的单位,是占用CPU的单位,例如8内核CPU,如果有8个线程,这个8个线程是并行(不是并发)。例如TCP多线程服务器,父程序中监听端口,如果有连接建立,就开一个新的线程进行对话处理。父程序中继续监听,有一个连接就建立一个线程。

问题来了,那么在单核CPU和多核CPU中,多进程和多线程怎么占用CPU资源呢?


4.单核cpu:

实现多进程依靠于操作系统的进程调度算法,比如时间的轮转算法,比如有3个正在运行的程序(即三个进程),操作系统会让单核cpu轮流来运行这些进程,然后一个进程只运行2ms,这样看起来就像多个进程同时在运行,从而实现多进程.

多线程其实是最大限度的利用cpu资源.一个拥有两个线程的进程的执行时间可能比一个线程的进程执行两遍的时间还长一点,因为线程的切换也需要时间.即采用多线程可能不会提高程序的运行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间.两个线程也是时间轮询占用CPU资源

5.多核cpu:

什么是多核cpu?多核cpu是一枚处理器中集成多个完整的计算引擎(内核)。多核cpu和单核cpu对于进程来说都是并发,并不是并行.

但是多核cpu每一个核心都可以独立执行一个线程,所以多核cpu可以真正实现多线程的并行.比如四核可以把线程1234分配给核心1234,如果还有线程567就要等待cpu的调度.线程1234属于并行;如果一会核心1停止执行线程1改为执行线程5,那线程15属于并发.



A.多进程TCP服务器

from socket import *
from multiprocessing import Process
def dealClient(newSocket,cliAddr):
    while True:
        recvData = newSocket.recv(1024)
        if len(recvData):
            print('收到来自%s的消息:%s' % (str(cliAddr), recvData))
        else:
            #如果数据长度为0 说明客户端断开连接,此时跳出循环关闭套接字
            print('客户端%s下线了......' % (str(cliAddr)))
            break
    newSocket.close()
  
def main():
    tcpSocket = socket(AF_INET,SOCK_STREAM)
 
    #设置套接字可以地址重用
    tcpSocket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    serverAddr = ('127.0.0.1',8888)
    tcpSocket.bind(serverAddr)
    tcpSocket.listen(100)
    #设置监听队列长度,在linux中这个值没有太大意义,kernel有自己的值
 
   #为了防止服务端异常退出,因此使用try...finally,确保创建的套接字可以正常关闭
    try:
        while True:
            # 在主进程中不断接收新的连接请求
            newSocket,cliAddr = tcpSocket.accept()
            #创建的进程处理已经建立好的连接,tcpSocket依旧去监听是否有新的请求。
            p1 = Process(target=dealClient,args=(newSocket,cliAddr))
            p1.start()
 
            newSocket.close()
            #创建子进程后,父进程也同样拥有newSocekt,但是子进程使用accept()返回的新套接字发送数据,因此父进程要把newSocket关闭
    except:
        pass
    finally:
        tcpSocket.close()
 
 
if __name__ == '__main__':
    main()


B.多线程TCP服务器

from socket import *
from threading import Thread
 
def dealClient(newSocket,cliAddr):
    while True:
        recvData = newSocket.recv(1024)
        if len(recvData):
            print('收到来自%s的消息:%s' % (str(cliAddr), recvData))
        else:
            #如果数据长度为0 说明客户端断开连接,此时跳出循环关闭套接字
            print('客户端%s下线了......' % (str(cliAddr)))
            break
    newSocket.close()
 
def main():
    tcpSocket = socket(AF_INET,SOCK_STREAM)
 
    #设置套接字可以地址重用
    tcpSocket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    serverAddr = ('127.0.0.1',8888)
    tcpSocket.bind(serverAddr)
    tcpSocket.listen(100)
    #设置监听队列长度,在linux中这个值没有太大意义,kernel有自己的值
 
   #为了防止服务端异常退出,因此使用try...finally,确保创建的套接字可以正常关闭
    try:
        while True:
            # 在线程中不断接收新的连接请求
            newSocket,cliAddr = tcpSocket.accept()
            #创建子线程处理已经建立好的连接,tcpSocket依旧去监听是否有新的请求。
            t1 = Thread(target=dealClient,args=(newSocket,cliAddr))
            t1.start()
 
    except:
        pass
    finally:
        tcpSocket.close()
 
if __name__ == '__main__':
    main()
举报
评论 0