【通信编程】“不一样的老板和员工流水线”——进程和线程

本文介绍了通信编程中的进程和线程概念,深入探讨了CPU时间片、进程与线程的区别以及多进程、多线程的实现方式。通过实例展示了如何在Python中创建多进程和多线程,强调了并发服务器和GIL锁在Python多线程中的影响。同时,文章提到了进程携带参数和线程携带参数的应用,并提供了并发服务器的多种实现总结链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

文章目录

  • 什么是通信
  • 多任务深入了解

  • 多进程实现

  • 多线程实现

  • 并发服务器
  • main
  • 阿言总结
  • 拓展

 前言

阿言emo了,昨天的课程也就丝毫没有兴趣的结束了。这里说明:学习是一个有氛围的活动

分享一个小伙伴的博客:Python UDP和黏包 一起来学习进步吧_杨某人...的博客-优快云博客

不闲说了:复习昨天知识点详见:http://t.csdn.cn/8f9NA

 

提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是通信

  • 通信就是指双方或者多方相互交流信息的过程,并且通过通信,获得和理解对方传递的信息为目的,例:我和你说话就是一种通信。

二、多任务深入了解

1.CPU时间片

31f3910ba56047d3a8de3969380ad0c5.png

  •  时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。而不会造成CPU资源浪费。

2.进程概念

什么是进程:

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体  详见:进程_360百科   (老配方了)

进程概念:

狭义定义:进程就是程序的执行过程。

进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

进程的概念主要有两点:

  • 第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
  • 第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。

进程主要特征:

动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。

并发性:任何进程都可以同其他进程一起并发执行

独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进

结构特征:进程由程序、数据和进程控制块三部分组成。

多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。

总:

  • 每个进程拥有自己的独立的地址空间,内存,数据在栈,以及其他用于跟踪执行的辅助数据
  •  各个进程之间相互独立,互不影响

  三.多进程实现

  • 单一进程:

使用睡眠来模拟耗时操作,查看真个程序的运行时间

import time

def new_time():
    return time.asctime(time.localtime(time.time()))


def func():
    print("inner_start", new_time())
    time.sleep(5)
    print("ineer_end", new_time())

func()


time.sleep(5)
print('outer',new_time())

  • 开启多进程

使用多进程来分担耗时任务,在另一个进程中运行耗时任务。这样主进程就不会收到影响

当子进程执行完时,返回子进程的运行结果

import time
import multiprocessing  # 导入多进程模块
import threading  # 导入多线程模块


def new_time():
    return time.asctime(time.localtime(time.time()))


def func():
    print("inner_start", new_time())
    time.sleep(5)
    print("ineer_end", new_time())


print("outer_start", new_time())


p1 = multiprocessing.Process(target=func)
p1.start() # 开启子进程
    
time.sleep(5)
print("outer_end", new_time())

3.1 多进程

7c17913218ce4bb7832028e031efeb34.png

 

首先是 multiprocess.Process实例化,并且指定回调函数,参数列表。

实例化之后可以直接调用运行,这就实现了多进程运行,节省运行时间

这里并行都只是python层面的,并不是实际层面的

当总进程多于核心数的时候,多于的没有效果

多进程有操作系统调用运行

四.多线程实现

这里直接详细见老配方:线程(计算机术语)_360百科

  • 线程概念

如果把进程比做一个工厂,那么线程就是工厂里面的工人,也就是一个进程可以包含多个线程

车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存

一个线程可以 被抢占(中断)也可以临时挂起(睡眠)

线程的调度由Python解释器调度,而进程由操作系统调度

4.1代码实现

模拟阻塞任务:

多线程不适合解决计算密集型的情形,但是适合IO密集型的场景。因为在同一进程内,并不会额外分配其他系统资源。

Python中的多线程在遇到阻塞的时候,会自动切换到非阻塞的线程上去

import time
import multiprocessing  # 导入多进程模块
import threading  # 导入多线程模块


def new_time():
    return time.asctime(time.localtime(time.time()))


def func(X):
    print(X)
    print("inner_start", new_time())
    time.sleep(5) #模拟阻塞任务
    print("ineer_end:", new_time())


print("outer_start", new_time())

t = threading.Thread(target=func,args=(1,))  #实例化
t.start()  # 开启新的线程

time.sleep(5)

print("outer_end", new_time())

Python发明之处,还没有多核CPU的概念。为了利用多核,Python开发支持多线程。而解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁。于是有了GIL这把超级大锁

GIL锁要求,任何进程中,一次只能有一个线程执行。因此,并不能为多个线程分配多个CPU。所以Python的线程只能实现并发,而不能实现真正的并行

五.并发服务器

import socket 
import multiprocessing 
server = socket . socket ( socket . AF _ INET , socket . SOCK _ STREAM )
#设置端口可复用, 
server . setsockopt ( socket . SOL _ SOCKET , socket .S0_ REUSEADDR ,1)
server . bind (('127.0.0.1',10086)) 
server . listen (10) 


bef handle ( conn ): 
    while True :
        #数据处理 
        recv _ data = conn . recv (1024)
        if recv_data: 
             print (recv_da)
             con.send(recv_data)
        else:
            conn.close()
            break

六.main

六.1写法

新建一个python文件
先编写main函数要执行的逻辑
然后通过if __name__ == '__main__':执行main函数逻辑
注意下划线是两条



print('hello,world')


def main():
    print('欢迎来到星月的博客')


if __ name__ == '__ main__':
    main()
   


六.2什么场景下会有main函数?

当该python脚本被作为模块(module)引入(import)时,其中的main()函数将不会被执行

六.3main函数的作用?

_ name__ == '__ main__'是Python的main函数入口。并非说,加入这句才能使用python xxx.py来执行,而是说,这里可以判断,当前是否是直接被python直接调用执行。

七.阿言总结:

7.1.进程

import time
import multiprocessing  # 导入多进程模块
import threading  # 导入多线程模块


def new_time():
    return time.asctime(time.localtime(time.time()))


def func():
    print("inner_start", new_time())
    time.sleep(5)
    print("ineer_end", new_time())


# print("outer_start", new_time())
# func()
# time.sleep(5)
# print("out_end", new_time())

7.2.进程案例

import time
import multiprocessing

def dance():
    for i in range(5):
        print("跳舞中....")
        time.sleep(0.2)


def sing():
    for i in range(5):
        print("唱歌中....")
        time.sleep(0.2)

if __name__ == '__main__':
    # 创建跳舞子进程
    dance_process = multiprocessing.Process(target=dance)
    sing_process = multiprocessing.Process(target=sing)


    dance_process.start()
    sing_process.start()

7.3.进程携带参数

import time
import multiprocessing  # 导入多进程模块


def new_time():
    return time.asctime(time.localtime(time.time()))


def func(x):
    print("内部开始", new_time())
    print(x)
    time.sleep(5)
    print("内部结束", new_time())


if __name__ == '__main__':
    print("外部开始", new_time())
    #     实例化进程对象

    p1 = multiprocessing.Process(target=func, kwargs={"x":18})
    p1.start()  # 开启子进程
    time.sleep(5)
    print("外部结束", new_time())

7.4.进程携带参数案例

import multiprocessing


def show_info(name, age):
    print(name, age)


if __name__ == '__main__':
    # 创建子进程
    # sub_process = multiprocessing.Process(target=show_info,args=("李四",14))
    # sub_process = multiprocessing.Process(target=show_info, kwargs={"age": 15, "name": "lisi"})
    sub_process = multiprocessing.Process(target=show_info, args=("李四",),kwargs={"age": 15})
    sub_process.start()

7.5.携带参数进程

import multiprocessing
import time

def task(count):
    for i in range(count):
        print("任务执行中....")
        time.sleep(0.2)

    else:
        print("任务执行完成")


if __name__ == '__main__':
    sub_process = multiprocessing.Process(target=task,args=(5,))
    sub_process.start()

7.6.线程携带参数示例

import threading
import time

def task(count):
    for i in range(count):
        print("任务执行中....")
        time.sleep(0.2)

    else:
        print("任务执行完成")


if __name__ == '__main__':
    # 创建子线程
    # args:以元祖的方式给任务传入参数
    # sub_process = threading.Thread(target=task,args=(5,))
    # kwargs:表示以字典的方式传入参数
    sub_process = threading.Thread(target=task,kwargs={"count":3})
    sub_process.start()

7.7.dmeo

#1.
import multiprocessing
import time

# 定义全局变量列表
g_list = []


# 添加数据的任务
def add_data():
    for i in range(3):
        # 因为列表是可变类型,可以在原有内存的基础上修改数据,并且修改后内存地址不变
        # 所以不需要加上global关键字
        # 加上global 表示声明要修改全局变量的内存地址
        g_list.append(i)
        print("add", i)
        time.sleep(0.2)
    print("添加完成", g_list)

# 读取数据的任务
def read_data():
    print("read",g_list)


if __name__ == '__main__':
    add_process = multiprocessing.Process(target=add_data)
    read_process = multiprocessing.Process(target=read_data)
    add_process.start()
    read_process.start()



#2.
import multiprocessing
import time

def task():
    time.sleep(1)
    print("当前进程:",multiprocessing.current_process().name)


if __name__ == '__main__':
    # 循环创建大量的进程,测试进程之间执行是否无序
    for i in range(5):
        p1 = multiprocessing.Process(target=task)
        # print(p1.name)
        p1.start()

扩展(以下是查询)详见:并发服务器几种实现方法总结 - 落叶虽美只活一世 - 博客园

 简单的单进程TCP服务器

from socket import socket, AF_INET,SOCK_STREAM,SOL_SOCKET,SO_REUSEADDR

#创建tcp服务器套接字
server_socket = socket(AF_INET,SOCK_STREAM)
#绑定端口
server_socket.bind(("",9999))
#设置正常情况退出的服务器下,端口可以重用
server_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
#设置监听,变为主动监听
server_socket.listen(5)

while True:
   # 等待客户端的链接,返回新的socket和地址
   new_socket,new_address = server_socket.accept()
   #接收数据,并且发送数据
   try:
      while True:
         recv_data = new_socket.recv(1024)
         #当有客户端关闭后,recv解除阻塞,并且返回长度为0
         if len(recv_data) > 0:
            recv_content = recv_data.decode("gb2312")
            print("收到:%s的信息是:%s" % (str(new_address),recv_content))
            new_socket.send("thank you!".encode("gb2312"))
         else:
            print("客户端%s已经关闭" % (str(new_address)))
            break
   finally:
      new_socket.close()
      print("关闭%s客户端" % (str(new_address)))

#关闭tcp服务器套接字
server_socket.close()

多进程TCP服务器

from socket import socket, AF_INET,SOCK_STREAM,SOL_SOCKET,SO_REUSEADDR
from multiprocessing import Process

#在子进程中接收消息
def recv_data(new_socket,new_address):
   while True:
      recv_data = new_socket.recv(1024)
      # 当有客户端关闭后,recv解除阻塞,并且返回长度为0
      if len(recv_data) > 0:
         recv_content = recv_data.decode("gb2312")
         print("收到:%s的信息是:%s" % (str(new_address), recv_content))
         new_socket.send("thank you!".encode("gb2312"))
      else:
         print("客户端%s已经关闭" % (str(new_address)))
         break
   #关闭与客户端的连接
   print("关闭与客户端的连接")
   new_socket.close()

def main():
   #创建tcp服务器套接字
   server_socket = socket(AF_INET,SOCK_STREAM)
   #绑定端口
   server_socket.bind(("",8888))
   #设置正常情况退出的服务器下,端口可以重用
   server_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

   #设置监听,变为被动连接
   server_socket.listen(3)

   try:
      while True:
         # 等待客户端的链接,返回新的socket和地址
         new_socket,new_address = server_socket.accept()
         #接收数据,并且发送数据
         Process(target=recv_data,args=(new_socket,new_address)).start()
         #因为主进程和子进程不共享数据
         #如果我们直接关闭new_socket,只是关闭主进程的new_socket,而子进程的不受影响
         new_socket.close()
   finally:
      #关闭tcp服务器套接字
      server_socket.close()

if __name__ == "__main__":
   main()

#2.多进程TCP服务器
from socket import socket, AF_INET,SOCK_STREAM,SOL_SOCKET,SO_REUSEADDR
from multiprocessing import Process

#在子进程中接收消息
def recv_data(new_socket,new_address):
   while True:
      recv_data = new_socket.recv(1024)
      # 当有客户端关闭后,recv解除阻塞,并且返回长度为0
      if len(recv_data) > 0:
         recv_content = recv_data.decode("gb2312")
         print("收到:%s的信息是:%s" % (str(new_address), recv_content))
         new_socket.send("thank you!".encode("gb2312"))
      else:
         print("客户端%s已经关闭" % (str(new_address)))
         break
   #关闭与客户端的连接
   print("关闭与客户端的连接")
   new_socket.close()

def main():
   #创建tcp服务器套接字
   server_socket = socket(AF_INET,SOCK_STREAM)
   #绑定端口
   server_socket.bind(("",8888))
   #设置正常情况退出的服务器下,端口可以重用
   server_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

   #设置监听,变为被动连接
   server_socket.listen(3)

   try:
      while True:
         # 等待客户端的链接,返回新的socket和地址
         new_socket,new_address = server_socket.accept()
         #接收数据,并且发送数据
         Process(target=recv_data,args=(new_socket,new_address)).start()
         #因为主进程和子进程不共享数据
         #如果我们直接关闭new_socket,只是关闭主进程的new_socket,而子进程的不受影响
         new_socket.close()
   finally:
      #关闭tcp服务器套接字
      server_socket.close()

if __name__ == "__main__":
   main()

多线程TCP服务器

from socket import socket, AF_INET,SOCK_STREAM,SOL_SOCKET,SO_REUSEADDR
from threading import Thread

#接收消息
def recv_data(new_socket,new_address):
   while True:
      recv_data = new_socket.recv(1024)
      # 当有客户端关闭后,recv解除阻塞,并且返回长度为0
      if len(recv_data) > 0:
         recv_content = recv_data.decode("gb2312")
         print("收到:%s的信息是:%s" % (str(new_address), recv_content))
         new_socket.send("thank you!".encode("gb2312"))
      else:
         print("客户端%s已经关闭" % (str(new_address)))
         break

def main():
   #创建tcp服务器套接字
   server_socket = socket(AF_INET,SOCK_STREAM)
   #绑定端口
   server_socket.bind(("",9999))
   #设置正常情况退出的服务器下,端口可以重用
   server_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

   #设置监听,变为被动连接
   server_socket.listen(3)

   try:
      while True:
         # 等待客户端的链接,返回新的socket和地址
         new_socket,new_address = server_socket.accept()
         #接收数据,并且发送数据
         Thread(target=recv_data,args=(new_socket,new_address)).start()
   finally:
      #关闭tcp服务器套接字
      server_socket.close()

if __name__ == "__main__":
   main()

单进程TCP服务器 ——非堵塞式

from socket import AF_INET,socket,SO_REUSEADDR,SOCK_STREAM,SOL_SOCKET

def main():

   #创建tcp的socket套接字
   server_socket = socket(AF_INET,SOCK_STREAM)
   server_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

   #绑定端口
   server_socket.bind(("",9999))

   #设置非阻塞,也就是说accept方法不阻塞了,
   # 但是在没有客户端链接且被执行的时候会报错
   #有客户端链接的时候正常执行
   server_socket.setblocking(False)

   #设置监听
   server_socket.listen(5)

   #客户端列表
   client_lists = []
   try:

      #不断调用accept
      while True:
         try:
            # print("accept--111")
            new_socket,new_address = server_socket.accept()
            print("accept--2222")
         except Exception as result:
            # print(result)
            pass
         else:
            print("新的客户%s链接上" % str(new_address))
            #新链接的new_sokect默认也是阻塞,也设置为非阻塞后,recv为非阻塞
            new_socket.setblocking(False)
            client_lists.append((new_socket,new_address))
         # print(111)
         for client_sokect,client_address in client_lists:
            #接收数据
            try:
               recv_data = client_sokect.recv(1024)
            except Exception as result:
               # print(result)
               pass
            else:
               # print("正常数据:%s" %recv_data)
               if len(recv_data) > 0 :
                  print("收到%s:%s" % (str(client_address),recv_data))
                  client_sokect.send("thank you!".encode("gb2312"))
               else:
                  #客户端已经端口,要把该客户端从列表中异常
                  client_lists.remove((client_sokect,new_address))
                  client_sokect.close()
                  print("%s已经断开" % str(new_address))

   finally:
      #关闭套接字
      server_socket.close()

if __name__ == "__main__":
   main()

协程:

存在线程中,是比线程更小的执行单元,又称微线程,纤程。自带cpu上下文,操作协程由程序员决定,它可以将一个线程分解为多个微线程,每个协程间共享全局空间的变量,每秒钟切换频率高达百万次。

 

                           谢谢大家支持,星月继续加油。

啰嗦几句,学习是个需要氛围的活动,为此51班全体学员安抚我们emo的阿言,下星期我们再见。

回文一下推荐分享一个小伙伴的博客:高级编程:认识进程与线程_杨某人...的博客-优快云博客

                                     51班全体学员加油!!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值