Python——多线程多进程与网络套接字编程

一、多进程和多线程

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

在Python中是能够使用多线程,来调度多核CPU来同时工作。

import time
from multiprocessing import Process

# process  进程 启用多进程在控制台中一共输出Boom XiaKaLaKa,10次
count = 0
def output(string):
    global count
    inner_count = 0
    while count < 10:
        print(string, end='', flush=True)
        count += 1
        inner_count += 1
        time.sleep(0.5)
    print('\n%s打印了%d次\n' % (string, inner_count))

def main():
    Process(target=output, args=('Boom',)).start()  # 开启多进程调用start()方法
    Process(target=output, args=('XiaKaLaKa',)).start()

if __name__ == '__main__':
    main()

在Python中也能使用多线程来实现异步任务处理, 但是只能调用一个CPU来全力执行线程中的任务

from threading import Thread
from time import sleep

def output():
    while True:
        print('Boom', end='', flush=True)
        sleep(0.001)

def main():
    Thread(target=output).start()  # 启用多线程调用output函数
    while True:
        print('XiaKaLaKa', end='', flush=True)
        sleep(0.001)

if __name__ == '__main__':
    main()

当然了,这样写,参数太长了,一般情况下,都是将线程写成一个类,这样,能对线程进行更加丰富的封装和定制

from threading import Thread
from time import sleep
from random import randint

# 创建线程的两种方式
# 1\. 直接创建Thread对象并通过target参数指定线程启动后要执行的任务
# 2\. 继承Thread自定义线程 通过重写run方法指定线程启动后执行的任务

class PrintThread(Thread):  # 创建类, 继承线程

    def __init__(self, string, count):  # 初始化参数
        super().__init__()
        self._string = string  # 需要打印的字符串
        self._count = count  # 计数

    def run(self):
        for _ in range(self._count):
            print(self._string, end='', flush=True)
            sleep(randint(0,2))  # 随机休眠,让每个线程都有占用CPU资源的机会

def main():
    PrintThread('Boom', 100).start()  # 开启自定义的线程
    PrintThread('XiaKaLaKa', 100).start()

if __name__ == '__main__':
    main()

下面我们来模拟一个下载文件的行为

import time
import random
from threading import Thread
from multiprocessing import process

# 如果多个任务之间没有任何的关联(独立子任务)而且希望利用cpu的多核特性
# 那么我们推荐使用多进程

class DownloadTask(Thread):
    def __init__(self, filename):  # 初始化线程构造方法
        super().__init__()
        self.filename = filename

    def run(self):
        print('开始下载%s...' % self.filename)
        delay = random.randint(5, 15)  # 随机数模拟下载时间
        time.sleep(delay)  # 线程休眠
        print('%s下载完成,用时%d秒.' % (self.filename, delay))

def main():
    start = time.time()  # 保存开始时间
    t1 = DownloadTask('Python从入门到住院.pdf')
    t2 = DownloadTask('Android从入门到放弃.pdf')

    t1.start()  # 开启线程
    t2.start()
    t1.join()  # 等待子线程执行完成
    t2.join()
    end = time.time()  # 保存结束时间
    print('总共耗费了%f秒' % (end - start))  # 计算耗费的时间

if __name__ == '__main__':
    main()

资源的保护,当我们同时开启多个线程同时去访问一个资源的时候,那个资源就是一个临界资源,临界资源,是无法正确的被多线程给读写的,这时候就资源添加一个锁,当有线程在使用的时候就将资源锁起来,使用完后又释放出去,这样就能保证数据的有效读写。

import time
from threading import Thread, Lock

class Account(object):  # 账户类
    def __init__(self):  # 初始化账户
        self._balance = 0
        self._lock = Lock()

    @property
    def balance(self):  # 获取余额
        return self._balance

    def deposit(self, money):  # 存钱
        # 当多个线程同时访问一个资源的时候,就有可能因为竞争,导致资源的状态错误
        # 被多个线程访问的资源,我们通常称之为临界资源,对临界资源的访问需要加上保护
        if money > 0:
            self._lock.acquire()  # 开启资源的锁保护
            try:
                new_balance = self._balance + money
                time.sleep(0.01)
                self._balance = new_balance
            finally:
                self._lock.release()  # 释放资源的锁保护

class AddMoneyThread(Thread):  #  存钱线程
    def __init__(self, account):  # 初始化传入账户对象
        super().__init__()
        self._account = account

    def run(self):
        self._account.deposit(1)  #  线程执行时存入一块钱

def main():
    account = Account()  # 新建账户对象
    tlist = []  # 线程列表
    for _ in range(100):  # 循环100次,进行存钱操作
        t = AddMoneyThread(account)  # 新建一个线程,传入账户对象
        tlist.append(t)  # 添加 到线程列表中
        t.start()  # 开起线程
    for t in tlist:
        t.join()  #  等待线程执行结束
    print('账户余额%d元' % account.balance)  # 打印出当前账户的余额

if __name__ == '__main__':
    main()

二、套接字(Socket)编程

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

# 服务端,等待客户端的接入

from socket import socket, AF_INET, SOCK_STREAM  # 需要导入socket包
from time import sleep, localtime, time
from datetime import datetime

def main():
    # 创建基于TCP协议的套接字对象
    # 因为我们做的是应用级产品或服务所以可以利用现有的传输服务来实现数据传输
    server = socket(AF_INET, SOCK_STREAM)  # 这两个是默认参数,默认的TCP连接,也可以直接socket()来创建对象
    # 绑定IP地址(网络上主机的身份标识)和端口(用来区分不同服务的IP地址扩展)
    server.bind(('10.7.189.55', 6310))
    # 开始监听客户端的连接,队列数量为512
    server.listen(512)
    print('服务器已经启动正在监听...')
    client, addr = server.accept()  # 开始等待接入
    while True:
        # 通过accept方法接收客户端的连接
        # accept方法是一个阻塞式的方法 如果没有客户端连接上老
        # 那么accept方法就好让代码阻塞 直到有客户端连接成功才返回对象
        # accept方法返回的一个原则,元组中的第一个值是代表客户端的对象
        # 元组中的第二值又是一个元组 其中有客户端的IP地址和客户端的地址
        # client, addr = server.accept()
        print(addr, '连接')
        date_time = datetime
        print(client.recv(512).decode('utf-8'))
        message = input("需要的发的消息")
        client.send(str(message).encode('utf-8'))
        # client.close()

if __name__ == '__main__':
    main()

# 客户端的连接
from socket import socket

def main():
    client = socket()  # 创建socket对象
    client.connect(('10.7.189.55', 6310))  # 连接服务器地址
    data = client.send('你1234e44好'.encode('utf-8'))  # 发送消息
    print(type(data))
    print(data)
    client.close()  # 关闭连接

if __name__ == '__main__':
    main()

服务器的输出如下:

服务器已经启动正在监听…
(‘10.7.189.55’, 50984) 连接
你1234e44好

这样就完成了一个简单的Socket连接

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容