实用篇 | 一文学会人工智能中API的Flask编写(内含模板)

 ----------------------- 🎈API 相关直达 🎈--------------------------

🚀Gradio: 实用篇 | 关于Gradio快速构建人工智能模型实现界面,你想知道的都在这里-CSDN博客

🚀Streamlit :实用篇 | 一文快速构建人工智能前端展示streamlit应用-CSDN博客

🚀Flask: 实用篇 | 一文学会人工智能中API的Flask编写(内含模板)-CSDN博客

在日常人工智能演示中,比较常用的api展示方式如flask,gradio等Web调用方式。在本文中,详细描述了在编写flask api中语法及语音文本图像模版案例等~

Flask是微型的Python Web框架,如果模型本身就是用python语言构建的,那么利用FLask提供Api服务是一个不错的选择。

1.深度学习流程

2.Flask重要函数

2.1.flask

语法:

flask():创建一个 flask 应用程序实例

2.2.render_template

语法:

render_template(template_name_or_list, **context):渲染指定的模板文件,并将其传递给模板上下文的变量

#render_template 发送template模块下的html文件

2.3.app.route

语法:

route(rule, options):将一个 url 规则与视图函数绑定,其中 rule 是一个字符串,表示匹配该 url 规则的 url 字符串;而 options 则是一个字典,用于在请求对象中设置额外的参数。

定义路由和视图函数 要将URL映射到视图函数,可以使用@app.route()装饰器。视图函数是处理请求并返回响应的函数。也就是根URL映射到名为函数名的视图函数。

2.4.add_url_rule

add_url_rule与app.route都是flask为我们建立路由的方式,两者实现的功能是一样的。

语法:

add_url_rule(rule,endpoint=None,view_func=None)
一共是三个参数:

relu、endpoint、view_func,其中rule(path)、view_func是必须填写的参数。

不填写endpoint则会默认使用view_func的名字作为endpoint。
 

2.5.run

语法:

run(host=none, port=none, debug=none, **options):运行 flask 应用程序,并将其绑定到指定的主机和端口号上。默认情况下,主机为 "localhost",端口号为 5000

运行应用程序 最后一步是运行应用程序。在开发过程中,可以使用app.run()方法来启动应用程序。 

2.6.request

语法:

request:全局对象,代表客户端向服务器发出的 http 请求。可以使用该对象来访问请求的头部、请求参数、json 数据等等。

2.7.MethodView类视图

视图函数也可以结合类来实现,类视图的好处是支持继承,可以将共性的东西放到父类中,类视图需要使用app.add_url_rule()来进行注册,类视图分为标准类视图基于调度方法的类视图

标准类视图

标准类视图有标准的写法

  • 父类继承flask.views.View
  • 子类调用dispatch_request进行返回,完成业务逻辑
  • 子类需要使用app.add_url_rule进行注册,其中view_func参数不能直接传入子类的名称,需要使用as_view做类方法转换
  • 如果同时也指定了endpoint,endpoint会覆盖as_view指定的视图名,先endpoint名后as_view名

使用类视图,在父类中定义一个属性,在子类中完成各自的业务逻辑,同时都继承父类中的这一个属性

基于方法判断的类视图

如果同一个视图函数需要根据不同的请求方式进行不一样的逻辑处理,需要在视图函数内部进行判断,可以使用方法类视图实现,使用类继承flask.views.MethodView,定义和请求方式同名的小写方法来完成了逻辑处理。

实例:编辑一个页面直接访问是输出用户名密码页面,提交表单后是密码正确与否的提示

from flask.views import View, MethodView
from flask import Flask, render_template, request

app = Flask(__name__)


class MyView(MethodView):
    def get(self):
        return render_template('index.html')

    def post(self):
        username = request.form.get('username')
        password = request.form.get('password')
        if username == "gp" and password == "mypassword":
            return '密码正确'
        else:
            return '密码错误'


app.add_url_rule('/', endpoint='login', view_func=MyView.as_view('login'))


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

在html中定义form标签action属性关联url名

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% macro input(name, type='text', value='') %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

<form action="/" method="post">
<p>用户名:{{ input('username') }}</p>
<p>密码:{{ input('password', type='password') }}</p>
{{ input('submit', type='submit', value='提交') }}
</form>
</body>
</html>

2.8.请求用户输入

2.8.1.请求用户输入文本

文本的请求类型如下:

  • json
  • form

# 请求用户以json文件输入单一文本
input_text = request.json('text')
print("input_text ::: ", input_text)
        
# 请求用户以表单(form)形式和图片等别的一起输入的文本
input_text1 = request.form('text1')
print("input_text1 ::: ", input_text1)

2.8.2.请求用户输入语音文件


# 请求用户输入一个音频
audio_files = request.files.getlist('audio')
print("audio_files ::: ", audio_files)
        
# 请求用户输入的音频拉成一个列表
audio_files = request.files.getlist('audio')
print("audio_files ::: ", audio_files)

2.8.3.请求用户输入照片,视频

# 请求用户输入图像
image_files = request.files('')
print("image_files ::: ",image_files)


# 请求用户输入视频
video_files = request.files('')
print("video_files ::: ",video_files)

实例1:基础代码结构如下

API设置中常使用Flask()

from flask import Flask
 
app = Flask(__name__)
 
@app.route("/")
def hello():
    return "Hello"
 
if __name__ == "__main__":
    app.run(host="127.0.0.1", port="8080")

-> 在第 1 行导入Flask

-> 将第 3 行导入的 Flask 分配给 app 变量。

  (这样以后使用flask相关的服务端功能时,就可以调用app并使用该方法)

-> 第5行是前面总结的Python装饰器相关的概念。 

  :通过使用route方法作为装饰器函数,当“/”路由到对应的API时,会执行底层的hello()函数,因此返回“hello”。

from flask import Flask
import joblib

app = Flask(__name__)

@app.route("/getModel",methods=['GET'])
def getModel():
	#根据文件路径load模型
	model=joblib.load('/data/model.pkl')
    return "model 查询到了"

if __name__ == "__main__":
	app.run(host='0.0.0.0',port=5003)  # 指定ip:port
    app.run(threaded=True) #开启多线程
    
print('运行结束')

实例2:设置2个路由,查看请求方法

# 生成Flask rest-api
from flask import Flask, request
from flask_cors import CORS

## 拉取 app
app = Flask(__name__)
# 安全库
CORS(app)

@app.route("/predict" , methods=["GET", "POST"])
def predict():
    if request.method == "POST": 
            message = {
                "name" : "post请求"
            }
            return message
    if request.method == "GET":
            message = {
                "name" : "get请求"
            }
            return message
@app.route("/predict2" , methods=["GET", "POST"])
def predict2():
    if request.method == "POST":
            message = {
                "name" : "post请求 2"
            }
            return message

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=50)  # debug=True causes Restarting with stat

 运行结果

如果出错请参考【PS3】 

2.9.返回对象

  • jsonify()【6】如果返回的是一个字典,那么调用 jsonify 创建一个响应对象。
  • 返回函数的输出

3.输入与输出

3.1. 音频输入与输出

语音流输出音频

from flask import Flask,Response

app = Flask(__name__)
@app.route('/')

def stream_audio():
    def generate():
        with open('audio.wav','rb') as f:
            data=f.read(1024)
            while data:
                yield data
                data=f.read(1024)
    return Response(generate(),mimetype='audio/wav')

if __name__=='__main__':
    app.run()

在上面代码中,创建了一个路由,返回一个流式输出的音频文件,在geerate函数中,使用关键字yield将音频文件分块输出,response对象将会包装这个生成器,并设置正确的MIME类型。

将base64解码为wav音频文件[7]

def base64_to_audio(base64_str):  # 用 b.show()可以展示
    audio = base64.b64decode(base64_str, altchars=None, validate=False)
    wavfile = "filename.wav"
    with open(wavfile, "wb") as f:
        f.write(audio)
        return wavfile
    return None

4.Flask部署深度学习api接口

4.1.语音类

4.1.1.语音转文本(Speech-To-Text),自己需设置前端版本

app.py

from flask import (Blueprint, flash, redirect, render_template, request)
import requests

bp = Blueprint('home', __name__)
@bp.route('/', methods=['GET', 'POST'])
def home():
    url = "http://server_ip:port/api/stt"
    if request.method == 'POST':
        audio_file = request.files['audio']
        model_name = request.form['name']
        error = None
        if not audio_file:
            error = "Audio file is required"
        if error is not None:
            flash(error)
        else:
            files = {"audio": audio_file, "name": model_name}
            result = requests.post(url, files=files)
            return render_template("index.html", result=result)

     return render_template("index.html", result=None)

templates/index.py 

   <div class="form-div">
            <form action="", method="POST" enctype="multipart/form-data", method="POST">
                <label for="audio">Audio: </label>
                <input type="file", name="audio", required> <br>
                <label for="name">Model:</label>
                <select name="name" id="">
                    <option value="none" selected disabled hidden>Select model</option>
                    <option value="tiny">tiny</option>
                    <option value="tiny.en">tiny.en</option>
                    <option value="base">base</option>
                    <option value="small">small</option>
                    <option value="small.en">Small.en</option>
                    <option value="medium">medium</option>
                </select> <br>
                <button type="submit">Transcribe</button>
            </form>
       </div> 

 结果如图

4.1.2.语音合成(TTS),无需设置前端版本,post进行请求

import sys
from flask import Flask, request, jsonify,render_template
from flask.views import MethodView
from flask_cors import CORS
import argparse
import base64
import librosa
import numpy as np
import matplotlib.pyplot as plt
import io
import logging

import soundfile
import torch

from flask import Flask, request, send_file
from flask_cors import CORS
from flask.views import MethodView


# check device
if torch.cuda.is_available() is True:
    device = "cuda:0"
else:
    device = "cpu"


def get_text(text, hps):
    text_norm = text_to_sequence(text, hps.data.text_cleaners)
    if hps.data.add_blank:
        text_norm = commons.intersperse(text_norm, 0)
    text_norm = torch.LongTensor(text_norm)
    return text_norm

def infer(text, sdp_ratio, noise_scale, noise_scale_w, length_scale, sid):
    global net_g
    fltstr = re.sub(r"[\[\]\(\)\{\}]", "", text)
    stn_tst = get_text(fltstr, hps)

    speed = 1
    output_dir = 'output'
    sid = 0
    with torch.no_grad():
        x_tst = stn_tst.to(device).unsqueeze(0)
        x_tst_lengths = torch.LongTensor([stn_tst.size(0)]).to(device)
        audio = net_g.infer(x_tst, x_tst_lengths, noise_scale=.667, noise_scale_w=0.8, length_scale=1 / speed)[0][
                0, 0].data.cpu().float().numpy()

    return audio
    
app = Flask(__name__)
#CORS(app, resources={r'/*': {"origins": '*'}})


class run_api(MethodView):
    def __init__(self):
        pass
    
    def post(self):
        
        # 请求用户输入
        data = request.get_json()
        text = data['text']
        print("Input text:", text)
        
        
        # 语音参数
        sdp_ratio = 0.2
        noise_scale = 0.667
        noise_scale_w = 0.1     
        length_scale = 1.0
        sid = 0

        # 配置文件
        config_name = "./config.json"
        hps = HParam(config_name)
        hps.set_hparam_yaml(config_name)

        # 模型权重
        checkpoint_path = "./G_179000.pth"
        checkpoint = torch.load(checkpoint_path, map_location=device)
        # 
        text = get_text(text)
        out_wav_file = infer(text,sdp_ratio, noise_scale, noise_scale_w, length_scale, sid)
        print("Input text : ",text)
        return "Success", (hps.data.sampling_rate, out_wav_file)


    
app.add_url_rule("/", view_func=run_api.as_view("run_api"))
    

if __name__ == '__main__':

    app.run(port=6842, host="0.0.0.0", debug=False, threaded=False)

可参考1python - How to make a web app download mp3 file automatically [Flask on Google App Engine] - Stack Overflow

可参考2

Python Web版语音合成实例详解 - Python技术站 (pythonjishu.com)

 语音合成后返回一组Base64编码格式的语音数据,用户需要用编程语言或者sdk将返回的Base64编码格式的数据解码成byte数组,再保存为wav格式的音频。

4.2.文本类

4.2.1.文本生成

# -*- coding: utf-8 -*-
import sys
from flask import Flask, request, jsonify
from flask_cors import CORS
import argparse
import torch
import os
#os.system('apt-get update')
#os.system('apt install gcc')
#os.system('pip install  request')

from transformers import pipeline, AutoModelForCausalLM

parser = argparse.ArgumentParser()
parser.add_argument('--prefix', type=str, default='/')
parser.add_argument('--port', type=int, default=8555)
args = parser.parse_args()

chat_history = []
for i in range(3):
    chat_history.append({"###提问":"","###回答":""})

app = Flask(__name__)
CORS(app, resources={r'/*': {"origins": '*'}})

def ask(x, context='', is_input_full=False):
    history = str(chat_history[-1]) + '\n' + str(chat_history[-2]) + '\n' + str(chat_history[-3]) + '\n'
    ans = pipe(
        f"### 对话记录: {history}\n" + 
        f"### 提问: {x}\n\n### 上下文: {context}\n\n### 回答:" if context else f"### 提问: {x}\n\n### 回答:", 
        do_sample=True, 
        max_new_tokens=512,
        temperature=0.7,
        top_p=0.9,
        return_full_text=False,
        eos_token_id=2,
    )
    return ans[0]['generated_text']

@app.route(args.prefix, methods=["POST"])
def API():
    print(request, flush=True)
    text1 = request.json['text']
    result = ask(text1)
    chat_history.append({"###提问":str(text1),"###回答":str(result)})
    print(result, flush=True)
    output = {
        "text": [
            {
                "历史记录": str(chat_history[-3:])
            },
            {
                "输入": str(text1)
            },
            {
                "@LLM大语言模型": str(result)
            }
        ]
    }
    return jsonify(output)

if __name__ == '__main__':
    MODEL = 'GPT12.8B'

    model = AutoModelForCausalLM.from_pretrained(
        MODEL,
        torch_dtype=torch.float16,
        low_cpu_mem_usage=True,
    ).to(device=f"cuda", non_blocking=True)
    model.eval()

    pipe = pipeline(
        'text-generation', 
        model=model,
        tokenizer=MODEL,
        device=0
    )   
    app.run(host="0.0.0.0", port=args.port, debug=True)  # debug=True causes Restarting with stat

5.设置flask API时出现错误总结

出现400:Bed Request 坏请求

  • 请求的文件不存在,或者文件路径不对

出现500:internal server error内部服务器错误

  • 文件传输方法不对

***注意输入输出的请求及传输

6.总结

在制作人工智能模型flask api时,总结如下

  • 首先设置flask 所需类以及路由,运行端口等
  • 第二设置好模型所需的结构,一般情况下都在推理文件中,确保所需类都可以被调用
  • 第三确定模型的输入:图片视频文本,每个输入单独写请求

最容易出错的部分就是第三部分,因为模型的话只要调用原有的就可以,出现的大部分错误是在运行后出现400,405,500等错误,首先大概率是api编写错误,其次是网络等问题~

过程中遇到的错误与解决【PS】

【PS1】Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding

致命的Python错误: init_fs_encoding:无法获取文件系统的Python编解码器编码Python运行时状态:核心初始化的ModuleNotFoundError:没有名为'encodings‘的模块

如果将这两个环境变量设置为nil,问题应该会消失: set PYTHONHOME= set PYTHONPATH=

错误原因:pip不小心删除

sudo apt-get remove python-pip-whl
sudo apt -f install
sudo apt update && sudo apt dist-upgrade
sudo apt install python3-pip

pip install certifi

pip install chardet

pip install idna

pip instal urllib3

【PS2】 ImportError: cannot import name 'BaseResponse' from 'werkzeug.wrappers' (/usr/local/lib/python3.8/dist-packages/werkzeug/wrappers/__init__.py)

这个错误可以重新安装werkzeug

pip install --upgrade werkzeug==1.0.1

然后就好啦~

【PS3】get请求出现404

 python app.py 
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off

警告是因为在开发环境中,Flask应用程序是使用内置的服务器(如SimpleServer或Lighttpd)运行的,而不是使用WSGI服务器。和最终出现的404没有关系!!

原因分析

  • 上一个项目运行没有终止
  • 端口(12.0.0.1:5000)被占用

最终原因

Flask的代码编写错误

【PS4】Flask请求出现500

500错误是指服务器内部出错,无法完成请求的情况。这可能是由于程序错误、错误的配置等原因造成的。

 在此处是因为找不到样本中的html文件。

错误原因:文件格式错误

原格式

----app

    ---templates

        ----index.html

----run.py

修改后正确

---templates

    ----index.html

----run.py

在同一目录下!!

【PS5】Flask设置api时出现405,405等

有俩个路由的情况

出现405

提交信息后,未找到

【PS6】NameError: name 'api_monitor' is not defined

自定义方法,官方文档并没有此方法,自己重新定义或者删掉就可以~

参考文献

【1】app.py · RamAnanth1/Dolly-v2 at main (huggingface.co)

【2】 [Flask/Postman] Flask로 간단한 서버 구현, postman으로 테스트 (tistory.com)

【3】Flask 极致细节:1. 路由和请求响应规则,GET/POST,重定向_@app.route post_破浪会有时的博客-CSDN博客【4】Deploy a Flask REST API - The Docker way and the Serverless way (amlanscloud.com)

【5】Building Scalable REST APIs using Heroku Flask MongoDB: 6 Easy Steps - Learn | Hevo (hevodata.com)【6】Flask 学习-88. jsonify() 函数源码解读深入学习 - 上海-悠悠 - 博客园 (cnblogs.com) 

【7】 Base64 Encoding and Decoding Using Python | Envato Tuts+ (tutsplus.com)

【8】How to Build a Text to Speech App (Python & Flask) [TTS API Python Tutorial] (rapidapi.com) 

【9】Flask REST API Tutorial - Python Tutorial (pythonbasics.org) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/231531.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【优选算法系列】【专题二滑动窗口】第三节.904. 水果成篮和438. 找到字符串中所有字母异位词

文章目录 前言一、水果成篮 1.1 题目描述 1.2 题目解析 1.2.1 算法原理 1.2.2 代码编写 1.2.3 题目总结二、找到字符串中所有字母异位词 2.1 题目描述 2.2 题目解析 2.2.1 算法原理 2.2.2 代码编写 …

OpenAI 首席运营官(COO)Brad Lightcap认为商业人工智能被夸大了

美国消费者新闻与商业频道&#xff08;CNBC&#xff09;是美国NBC环球集团持有的全球性财经有线电视卫星新闻台&#xff0c;是全球财经媒体中的佼佼者&#xff0c;其深入的分析和实时报导赢得了全球企业界的信任。在1991年前&#xff0c;使用消费者新闻与商业频道&#xff08;C…

node.js和npm的安装与环境配置(2023最新版)

目录 安装node.js测试是否安装成功测试npm环境配置更改环境变量新建系统变量 安装node.js 1、进入官网下载&#xff1a;node.js官网 我选择的是windows64位的&#xff0c;你可以根据自己的实际情况选择对应的版本。 2、下载完成&#xff0c;安装。 打开安装程序 接受协议 选…

链表OJ—环形链表的约瑟夫问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 世上有两种耀眼的光芒&#xff0c;一种是正在升起的太阳&#xff0c;一种是正在努力学习编程的你!一个爱学编程的人。各位看官&#xff0c;我衷心的希望这篇博客能对你…

操作系统———磁盘调度算法模拟

实验目的 磁盘是可供多个进程共享的设备&#xff0c;当有多个进程都要求访问磁盘是&#xff0c;应采用一种最佳调度算法&#xff0c;以使各进程对磁盘的平均访问时间最小。目前最成用的磁盘调度算法有先来先服务&#xff08;FCFS&#xff09;&#xff0c;最短寻道时间优先&…

增加网站流量的方法

如果您的网站没有获得足够的流量&#xff0c;您可能会错过在线发展业务的重要机会。搜索引擎优化&#xff08;SEO&#xff09;可以帮助提高您网站的知名度&#xff0c;从而吸引更多客户。 SEO的重点是识别高价值的关键词&#xff0c;并将它们整合到网站的内容中&#xff0c;使…

【设计模式-3.2】结构型——适配器模式

说明&#xff1a;本文介绍设计模式中结构型设计模式中的&#xff0c;适配器模式&#xff1b; 插头转换器 适配器模式属于结构型设计模式&#xff0c;设计思想体现在结构上的。以插头转换器为例&#xff0c;当你需要给手机充电&#xff0c;但是眼前只有一个三孔插座&#xff0…

MES管理系统在非标制造企业中的应用

在当今制造业中&#xff0c;非标制造企业逐渐成为一种重要的存在。与传统的批量生产制造企业不同&#xff0c;非标制造企业主要特点是能够根据客户需求进行定制化生产。这种定制化的生产模式对企业的管理提出了更高的要求&#xff0c;同时也带来了更多的挑战。在非标制造企业中…

Emacs之Plantuml用于复杂UML类图(Markdown用于简单类图)(一百三十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

MQTT主题、通配符和最佳实践

MQTT主题在MQTT生态系统非常重要&#xff0c;因为代理&#xff08;broker&#xff09;依赖主题确定哪个客户端接收指定的主题。本文我们将聚集MQTT主题、MQTT通配符&#xff0c;详细讨论使用它们的最佳实践&#xff0c;也会探究SYS主题&#xff0c;提供给代理&#xff08;broke…

超越极限!如何进行高效分布式性能测试,让Jmeter揭示并发下系统的真正实力

一、为什么要进行分布式性能测试 当进行高并发性能测试的时候&#xff0c;受限于Jmeter工具本身和电脑硬件的原因&#xff0c;无法满足我们对大并发性能测试的要求。 基于这种场景下&#xff0c;我们就需要采用分布式的方式来实现我们高并发的性能测试要求。 二、分布式性能测…

深度学习记录--激活函数

激活函数的种类 对于激活函数的选择&#xff0c;通常有以下几种 sigmoid&#xff0c;tanh&#xff0c;ReLU&#xff0c;leaky ReLU 激活函数的选择 之前logistic回归一直使用的激活函数都是sigmoid函数&#xff0c;但一般来说&#xff0c;tanh函数是比sigmoid函数更加好的选…

【小白专用】在 vs 中使用 nuget 安装NPOI

C#操作Excel有多种方法&#xff0c;如通过数据库的方式来读写Excel的OleDb方式&#xff0c;但是OleDb方式需要安装微软office&#xff0c;还可以通过COM组件方式操作Excel&#xff0c;也需要安装微软Excel。如果不想安装微软办公套餐可以使用ClosedXML、EPPlus、NPOI。本文主要…

理解IoC容器初始化

问题&#xff1a;当自己面试或者背诵八股文时&#xff0c;会背到各种各样的spring底层的东西&#xff0c;自己越看越迷糊。 OS&#xff1a;不知道兄弟们是不是也会这样&#xff1f;如果大家没有说明我太菜了。 原因&#xff1a;就是自己学的框架越来越多&#xff0c;很多框架…

线性回归实战

3.1 使用正规方程进行求解 3.1.1 简单线性回归 公式 &#xff1a; y w x b y wx b ywxb 一元一次方程&#xff0c;在机器学习中一元表示一个特征&#xff0c;b表示截距&#xff0c;y表示目标值。 使用代码进行实现&#xff1a; 导入包 import numpy as np import matp…

bc-linux-欧拉重制root密码

最近需要重新安装虚拟机的系统 安装之后发现对方提供的root密码不对&#xff0c;无法进入系统。 上网搜了下发现可以进入单用户模式进行密码修改从而重置root用户密码。 在这个界面下按e键 找到图中部分&#xff0c;把标红的部分删除掉&#xff0c;然后写上rw init/bin/…

JAVEE初阶 多线程基础(七)

懒汉模式 指令重排序问题 一. 懒汉模式的意义和代码实现二. 饿汉模式和懒汉模式的线程安全三. 懒汉模式的线程安全问题解决3.1 加锁阶段3.2 嵌套if阶段3.3 指令重排序问题3.4 解决线程安全问题阶段 一. 懒汉模式的意义和代码实现 在上一章节中,我们先学习了单例模式中的饿汉模式…

【好书推荐】《深入Activiti流程引擎:核心原理与高阶实战》

学习工作流&#xff0c;推荐贺老师的书《深入Activiti流程引擎&#xff1a;核心原理与高阶实战》&#xff0c;对系统学习和深入掌握Activiti/Flowable流程引擎的用法非常有帮助。 图书链接

我的NPI项目之Android电源系列 -- 关于剩余充满时间的问题(一)

我的新项目是基于高通最新的5G平台&#xff0c;但是由于还没有拿到EVT。所以&#xff0c;就在目旧的平台和OS上进行学习。遇到第一个问题就是插上type-c之后&#xff0c;充满剩余时间异常的问题。 问题描述&#xff0c;在充电过程中&#xff0c;显示充满时间为“0 min left unt…

基于EIoT能源物联网的智能照明系统应用改造-安科瑞 蒋静

【摘要】&#xff1a;随着物联网技术的发展&#xff0c;许多场所针对照明合理应用物联网照明系统&#xff0c;照明作为工厂的重要能耗之一&#xff0c;工厂的照明智能化控制&#xff0c;如何优化控制、提高能源的利用率&#xff0c;达到节约能源的目的。将互联网的技术应用到工…
最新文章