10、Go Gin 连接Redis以及CookieSession

一、Redis

在Go语言中,使用Gin框架结合Redis数据库可以构建高性能的Web应用程序。Gin是一个轻量级的HTTP框架,提供了快速构建RESTful API的能力;而Redis则是一个高性能的键值存储系统,常用于缓存、消息队列、计数器等多种场景

1、安装Redis客户端库

要在Go语言的Gin框架中连接Redis并执行基本操作,你需要先安装Go的Redis客户端库。推荐使用go-redis/redis,这是一个高性能的Redis客户端 

go get -u github.com/go-redis/redis/v8

2、示例代码一

注意:确保你的Redis服务正在运行,并根据实际情况调整连接参数。 

package mainimport ("context""github.com/gin-gonic/gin"redis "github.com/go-redis/redis/v8""log"
)var rdb *redis.Clientfunc init() {// 初始化Redis客户端rdb = redis.NewClient(&redis.Options{Addr:     "localhost:6379", // Redis服务器地址和端口Password: "",               // 密码,如果没有设置则留空DB:       0,                // 使用默认数据库})
}func main() {ctx := context.Background()// 测试Redis连接_, err := rdb.Ping(ctx).Result()if err != nil {log.Fatalf("无法连接到Redis: %v", err)}router := gin.Default()// http://localhost:8080/set/aaa/123router.GET("/set/:key/:value", func(c *gin.Context) {key := c.Param("key")value := c.Param("value")err := rdb.Set(ctx, key, value, 0).Err()if err != nil {c.JSON(500, gin.H{"error": "设置键值对失败"})return}c.JSON(200, gin.H{"message": "设置成功"})})// http://localhost:8080/get/aaarouter.GET("/get/:key", func(c *gin.Context) {key := c.Param("key")val, err := rdb.Get(ctx, key).Result()if err == redis.Nil {c.JSON(404, gin.H{"message": "键不存在"})return} else if err != nil {c.JSON(500, gin.H{"error": "获取键值对失败"})return}c.JSON(200, gin.H{"key": key, "value": val})})router.Run(":8080")
}

3、示例代码二

注意:确保你的Redis服务正在运行,并根据实际情况调整连接参数。 

package mainimport ("context""github.com/gin-gonic/gin"redis "github.com/go-redis/redis/v8""log""net/http"
)var rdb *redis.Clientfunc init() {// 初始化Redis客户端rdb = redis.NewClient(&redis.Options{Addr:     "localhost:6379", // Redis服务器地址和端口Password: "",               // 密码,如果没有设置则留空DB:       0,                // 使用默认数据库})
}
func setKeyValue(c *gin.Context) {key := c.Query("key")value := c.Query("value")err := rdb.Set(context.Background(), key, value, 0).Err()if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "设置键值对失败"})return}c.JSON(http.StatusOK, gin.H{"message": "设置成功"})
}func getKey(c *gin.Context) {key := c.Query("key")val, err := rdb.Get(context.Background(), key).Result()if err == redis.Nil {c.JSON(http.StatusNotFound, gin.H{"message": "键不存在"})} else if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "获取键值对失败"})} else {c.JSON(http.StatusOK, gin.H{"key": key, "value": val})}
}
func main() {ctx := context.Background()// 测试Redis连接_, err := rdb.Ping(ctx).Result()if err != nil {log.Fatalf("无法连接到Redis: %v", err)}router := gin.Default()// http://localhost:8080/set?key=aaa&value=123456router.GET("/set", setKeyValue)// http://localhost:8080/get?key=aaarouter.GET("/get", getKey)router.Run(":8080")
}

 二、Cookie&Session

在Go语言中,使用Gin框架处理Cookie和Session是Web开发中的常见需求。下面我将分别介绍如何在Gin中使用Cookie和Session 

1、Cookie

HTTP 是无状态协议,简单地说,当浏览了一个页面,然后转到同一个网站的另一个页面,服务器无法认识到这是同一个浏览器在访问同一个网站,每一次的访问,都是没有任何关系的,如果要实现多个页面之间共享数据的话就可以使用 Cookie 或者 Session 实现cookie 是存储于访问者计算机的浏览器中,可以用同一个浏览器访问同一个域名的时候共享数据。

Cookie是一种在客户端存储数据的技术,它允许服务器通过HTTP响应头向客户端发送一些数据,客户端之后的请求会自动带上这些数据到服务器 。

(1)、设置获取Cookie

设置和获取 Cookie | Gin Web Framework

c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)

 SetCookie函数用于设置Cookie,参数依次为:

Cookie名称、值、过期时间(秒)、路径、域名、是否只通过HTTPS传输、是否只用于HTTP请求

(2)、 示例代码一,设置和获取

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()// http://localhost:8080/setcookier.GET("/setcookie", func(c *gin.Context) {// 设置一个名为"mycookie"的Cookie,值为"value", 过期时间为24小时后c.SetCookie("mycookie", "value", 3600*24, "/", "localhost", false, true)c.String(http.StatusOK, "Cookie设置成功")})// http://localhost:8080/getcookier.GET("/getcookie", func(c *gin.Context) {cookie, err := c.Cookie("mycookie")if err != nil {c.String(http.StatusBadRequest, "读取Cookie失败: %s", err)} else {c.String(http.StatusOK, "Cookie的值为: %s", cookie)}})r.Run(":8080")
}

(3)、 示例代码二,共享域名

要在Go语言的Gin框架中实现多个二级域名共享Cookie,关键在于设置Cookie时正确地使用Domain字段。当希望多个二级域名能够访问同一份Cookie时,你需要将Domain设置为它们共同的顶级域名(不包含任何子域名部分)

设置共享 cookie

当你设置 cookie 时,你需要将 Domain 设置为所有子域名共享的父域名(不包括子域名本身)。例如,如果你的子域名是 a.example.com 和 b.example.com,你可以将 Domain 设置为 .example.com(注意前面的点号) 

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/setcookie", func(c *gin.Context) {cookie := &http.Cookie{Name:     "shared_cookie",Value:    "some_value",Domain:   ".example.com", // 注意前面的点号Path:     "/",MaxAge:   86400, // 一天HttpOnly: true,}c.SetCookie(cookie.Name, cookie.Value, cookie.MaxAge, cookie.Path, cookie.Domain, cookie.Secure, cookie.HttpOnly)c.String(200, "Cookie set successfully")})// ... 其他路由r.Run(":8080") // 假设你在本地开发,并且使用 8080 端口
}
 通过二级域名访问共享 cookie
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()// 设置路由处理函数,用于在响应中设置共享的Cookie// http://localhost:8080/getSharedCookier.GET("/setSharedCookie", func(c *gin.Context) {// 注意:将Domain设置为顶级域名,例如 ".example.com",前面的点表示任何子域名都可以访问此Cookiec.SetCookie("sharedCookie", "sharedValue", 3600, "/", ".example.com", false, true)c.String(http.StatusOK, "Shared Cookie 设置成功")})// 正常访问:http://localhost:8080/getSharedCookie// 使用二级域名访问:http://二级域名:8080/getSharedCookie// 如:http://a.example.com:8080/getSharedCookie// 如:http://b.example.com:8080/getSharedCookier.GET("/getSharedCookie", func(c *gin.Context) {cookie, err := c.Cookie("sharedCookie")if err != nil {c.String(http.StatusBadRequest, "读取Cookie失败: %s", err)} else {c.String(http.StatusOK, "Cookie的值为: %s", cookie)}})// 启动服务器r.Run(":8080")
}

通过c.SetCookie函数设置了一个名为sharedCookie的Cookie,它的Domain被设为.example.com。这里的点(.)是必要的,它表明这个Cookie对于.example.com下的所有子域名都是可见的,比如a.example.comb.example.com都能访问这个Cookie 

注意事项

         a、确保你的应用可以在所有子域名上访问,或者确保只有需要访问共享 cookie 的子域名上有你的应用。
        b、出于安全考虑,你应该始终通过 HTTPS 传输 cookie,并设置 Secure 属性为 true。但请注意,在本地开发时,你可能无法使用 HTTPS,因此可以在开发环境中禁用它。
       c、 不要将敏感信息存储在客户端 cookie 中。即使你使用了加密,也不能保证 cookie 的安全性。对于敏感信息,应该使用服务器端会话或安全的数据库存储。

二级域名在项目中的使用 

通过二级域名访问共享 cookie 的地址实际上取决于你的应用部署在哪个二级域名下,并且你希望在哪个路由下访问这个 cookie。在 Gin Web 框架中,你定义了一个或多个路由(endpoints)来处理 HTTP 请求,并在这些路由的处理函数中访问或设置 cookie。

例如,如果你的 Gin 应用部署在 sub1.example.com 和 sub2.example.com 这两个二级域名下,并且你想通过一个特定的路由 /getcookie 来访问共享的 cookie,那么对于 sub1.example.com,访问地址将是 http://sub1.example.com/getcookie,对于 sub2.example.com,访问地址将是 http://sub2.example.com/getcookie

这里是一个简化的例子,展示了如何在 Gin 应用中定义这样一个路由来访问共享的 cookie:

package main  import (  "github.com/gin-gonic/gin"  
)  func main() {  r := gin.Default()  // 设置共享 cookie 的路由(这里只是一个示例,实际设置可能在其他地方)  r.GET("/setcookie", func(c *gin.Context) {  // ... 设置 cookie 的代码 ...  c.String(200, "Cookie set successfully")  })  // 访问共享 cookie 的路由  r.GET("/getcookie", func(c *gin.Context) {  cookie, err := c.Cookie("shared_cookie")  if err != nil {  c.String(400, "Cookie not found")  return  }  c.String(200, "Cookie value: "+cookie)  })  // 启动服务,这里假设你已经在两个二级域名下部署了这个应用  // 你需要分别在这两个二级域名下启动服务,或者使用反向代理等技术来将请求路由到同一个应用实例  r.Run(":8080") // 这只是一个示例端口,实际应用中需要配置为正确的监听地址和端口  
}

请注意,r.Run(":8080") 这行代码只会在本地主机的 8080 端口上启动服务。在实际部署中,你需要在两个二级域名下分别部署你的 Gin 应用,或者使用反向代理(如 Nginx)将两个二级域名的请求转发到同一个 Gin 应用实例。

此外,由于 cookie 的 Domain 属性设置为 .example.com,所以只要 cookie 已经被正确设置,并且浏览器支持跨域 cookie(即没有遇到跨域策略的限制),那么无论是通过 sub1.example.com/getcookie 还是 sub2.example.com/getcookie 访问,都应该能够获取到共享的 cookie。

 另外:如何在两个二级域名下分别部署你的 Gin 应用

在两个二级域名下分别部署 Gin 应用通常涉及在两台不同的服务器或两个不同的服务实例上运行你的 Gin 应用,或者配置一个反向代理(如 Nginx)来根据请求的域名将流量路由到同一个 Gin 应用实例的不同配置。

以下是两种常见的方法:

方法一:在两个不同的服务器或服务实例上部署
  1. 准备两个服务器或服务实例:确保你有两个独立的服务器或容器实例,例如两台云服务器或两个 Kubernetes Pod。

  2. 部署 Gin 应用:在两个服务器上分别部署你的 Gin 应用。你可以使用 Docker、Kubernetes、Ansible、Chef、Puppet 等工具来自动化部署过程。

  3. 配置域名:确保你的 DNS 记录已经正确设置,将 sub1.example.com 解析到第一个服务器的 IP 地址,将 sub2.example.com 解析到第二个服务器的 IP 地址。

  4. 启动 Gin 应用:在每个服务器上启动你的 Gin 应用,并监听相应的端口(例如 80 或 443,取决于你是否使用 HTTPS)。

方法二:使用反向代理(如 Nginx)
  1. 准备服务器:准备一台服务器来运行 Nginx 和你的 Gin 应用。

  2. 安装 Nginx:在服务器上安装 Nginx。

  3. 配置 Nginx:编辑 Nginx 的配置文件(通常是 /etc/nginx/nginx.conf 或 /etc/nginx/sites-available/ 目录下的某个文件),添加两个 server 块来分别处理 sub1.example.com 和 sub2.example.com 的请求。在每个 server 块中,使用 proxy_pass 指令将请求转发到你的 Gin 应用实例。

    示例 Nginx 配置可能如下所示:

    server {  listen 80;  server_name sub1.example.com;  location / {  proxy_pass http://localhost:8080; # 假设 Gin 应用在 8080 端口上运行  proxy_set_header Host $host;  proxy_set_header X-Real-IP $remote_addr;  # 其他必要的 proxy_set_header 指令  }  
    }  server {  listen 80;  server_name sub2.example.com;  location / {  proxy_pass http://localhost:8080; # 同样的 Gin 应用实例处理两个域名的请求  proxy_set_header Host $host;  proxy_set_header X-Real-IP $remote_addr;  # 其他必要的 proxy_set_header 指令  }  
    }

    注意:在这个配置中,我们假设 Gin 应用在服务器的 8080 端口上运行,并且处理来自两个域名的请求。在实际部署中,你可能需要根据你的实际情况调整端口和配置。

  4. 启动 Nginx 和 Gin 应用:首先启动你的 Gin 应用实例,并监听一个端口(例如 8080)。然后启动 Nginx,它将根据你的配置文件来处理来自 sub1.example.com 和 sub2.example.com 的请求,并将它们转发到你的 Gin 应用实例。

  5. 配置域名:确保你的 DNS 记录已经正确设置,将 sub1.example.com 和 sub2.example.com 都解析到运行 Nginx 的服务器的 IP 地址。

使用反向代理的方法通常更加灵活和可维护,因为它允许你在一个集中的地方管理路由和流量分配。然而,它也可能增加系统的复杂性和性能开销。根据你的具体需求和资源限制,选择最适合你的方法。

2、Session 

 Session是一种服务器端存储用户状态的机制,相比Cookie更安全,因为它不直接暴露在客户端。在Gin中使用Session,通常需要借助中间件,如github.com/gin-contrib/sessions

(1)、Session 的工作流程

当客户端浏览器第一次访问服务器并发送请求时,服务器端会创建一个 session 对象,生成一个类似于 key,value 的键值对,然后将 value 保存到服务器 将 key(cookie)返回到浏览器(客户)端,浏览器下次访问时会携带 key(cookie),找到对应的 session(value)

(2)、安装session包

go get -u github.com/gin-contrib/sessions
go get -u github.com/go-redis/redis/v8

(3)、设置session&获取session&删除session

package mainimport ("github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/cookie""github.com/gin-gonic/gin""net/http"
)func main() {// 加载引擎r := gin.Default()//创建基于cookie的存储引擎,mySessionKey参数是用于加密的密钥store := cookie.NewStore([]byte("mySessionKey"))//设置session中间件,参数mySession,指的是session的名字,也是cookie的名字//store是前面创建的存储引擎,我们可以替换成其他存储引擎r.Use(sessions.Sessions("mySession", store))// http://127.0.0.1:8080/setSessionr.GET("/setSession", func(c *gin.Context) {//设置sessionsession := sessions.Default(c)session.Set("username", "张三")//设置过期时间session.Options(sessions.Options{//MaxAge: 3600 * 6, //6hrsMaxAge: 30, //30s})session.Save() // 设置session的时候必须调用c.JSON(http.StatusOK, gin.H{"title": "设置session成功",})})// http://127.0.0.1:8080/getSessionr.GET("/getSession", func(c *gin.Context) {//获取session//初始化session对象session := sessions.Default(c)username := session.Get("username")if username == nil {c.JSON(http.StatusOK, gin.H{"username": username,"title":    "不存在该session",})return}c.JSON(http.StatusOK, gin.H{"title":    "获取session成功","username": username,})})// http://127.0.0.1:8080/deleteSessionr.GET("/deleteSession", func(c *gin.Context) {//删除sessionsession := sessions.Default(c)username := session.Get("username")if username == nil {c.JSON(http.StatusOK, gin.H{"username": username,"title":    "不存在该session",})return}session.Delete("username")session.Save()c.JSON(http.StatusOK, gin.H{"sessionKey": "username","title":      "删除session成功",})})r.Run(":8080")
}

(4)、session存储后端,如memory、redis、mysql

在Go语言中使用Gin框架来设置、获取和删除session,通常需要借助一些第三方的session管理中间件,比如github.com/gin-contrib/sessions。这个库支持多种session存储后端,如memory、redis、mysql等。下面以内存存储(memory)为例,介绍如何设置、获取和删除session

1). 安装依赖 

首先,你需要安装gingin-contrib/sessions以及其内存存储引擎gin-contrib/sessions/mongo(这里以mongo为例,实际可根据需求选择其他存储引擎):

注意:上述命令中的mongo应替换为你打算使用的存储引擎,如redis, mysql等。如果使用内存存储,应为cookiememory
 

如:如果想将 session 数据保存到 redis 中,只要将 session 的存储引擎改成 redis 即可

go get -u github.com/gin-gonic/gin
go get -u github.com/gin-contrib/sessions
go get -u github.com/gin-contrib/sessions/mongo
go get -u github.com/gin-contrib/sessions/redis

 2). 初始化Gin与Session

package mainimport ("github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/mongo""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 使用Mongo存储session,如果是内存存储,将mongo改为cookie或memorystore, _ := mongo.NewStore(10, "tcp", "localhost:27017", "test_session", "", []byte("secret"))// 注册session中间件r.Use(sessions.Sessions("mysession", store))r.GET("/set", func(c *gin.Context) {session := sessions.Default(c)session.Set("key", "value")session.Save()c.JSON(200, gin.H{"message": "session set"})})r.GET("/get", func(c *gin.Context) {session := sessions.Default(c)value := session.Get("key")c.JSON(200, gin.H{"message": value})})r.GET("/delete", func(c *gin.Context) {session := sessions.Default(c)session.Delete("key")session.Save()c.JSON(200, gin.H{"message": "session deleted"})})r.Run(":8080")
}

 

3). 功能说明

  • r.Use(sessions.Sessions("mysession", store)):这行代码注册了session中间件,"mysession"是session的名称,可以自定义,store则是具体的session存储实例。
  • /set路由:设置session。通过session.Set("key", "value")设置session的键值对,并通过session.Save()保存到存储引擎。
  • /get路由:获取session。通过session.Get("key")获取之前设置的session值。
  • /delete路由:删除session。通过session.Delete("key")删除指定的session键值对,并保存更改。

在Go Gin框架中,选择不同的session存储方式(MongoDB、内存、Cookie、Redis)各有其优缺点,具体如下:

3、选择存储引擎

MongoDB

  • 优点:

    • 持久化:数据存储在MongoDB数据库中,即使服务器重启,session数据依然保留。
    • 扩展性:MongoDB支持水平扩展,适合大量数据和高并发访问。
    • 灵活性:支持复杂查询,便于管理和分析session数据。
  • 缺点:

    • 性能:相较于内存存储,MongoDB的读写速度相对较慢。
    • 依赖:增加了对MongoDB数据库的依赖,需要维护数据库的稳定运行。

内存(Memory)

  • 优点:

    • 速度:内存访问速度快,能够提供极高的读写性能。
    • 简单:实现简单,无需配置额外的存储服务。
  • 缺点:

    • 非持久化:服务器重启后,所有session数据丢失。
    • 扩展性:不适合分布式部署,因为session数据不能跨服务器共享。

Cookie

  • 优点:

    • 无服务器存储:减轻服务器存储负担,所有数据存储在客户端。
    • 简单配置:实现简单,不需要额外的后端存储配置。
  • 缺点:

    • 安全性:数据暴露在客户端,容易被篡改或盗窃,不适合存储敏感信息。
    • 大小限制:受HTTP协议限制,Cookie大小有限,不适合存储大量数据。

Redis

  • 优点:

    • 高性能:基于内存存储,读写速度快,接近原生内存操作。
    • 持久化:支持数据持久化到磁盘,保证数据安全。
    • 扩展性:易于扩展,支持主从复制和集群模式,适合分布式系统。
    • 成熟方案:广泛应用于session存储,社区支持丰富。
  • 缺点:

    • 运维成本:需要维护Redis服务器,增加了运维工作量。
    • 额外依赖:引入了新的组件,增加了系统的复杂度。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日OJ题_贪心算法四⑧_力扣767. 重构字符串

目录 力扣767. 重构字符串 解析代码 力扣767. 重构字符串 767. 重构字符串 难度 中等 给定一个字符串 s ,检查是否能重新排布其中的字母,使得两相邻的字符不同。 返回 s 的任意可能的重新排列。若不可行,返回空字符串 "" 。 …

Jetson Orin NX L4T35.4.1平台自启动时间优化调试记录1

1.前言 尝试优化Orin NX (p3767+p3768)与R35.4.1 BSP的启动时间; 从USB引导Orin设备; 最初,引导时间是55-57秒; 在内核端进行了一些优化之后,我们现在是38-40秒; 正试图在15秒内启动Orin设备,但是UEFI本身需要12秒才能完成 UEFI 优化: (1)https://github.com/NVI…

鸿蒙系统编译方式

鸿蒙系统编译 编译原理编译方式概述hb编译ohos-buildhb安装编译使用build脚本hpmhpm介绍编译举例说明综合应用举例虚拟机中编译docker中使用hpm编译编译原理 编译构建指导:https://docs.openharmony.cn/pages/v4.0/zh-cn/device-dev/subsystems/subsys-build-all.md,文档介绍…

java 对象赋值

在Java中,对象赋值给另一个对象通常是通过引用的方式来实现的。这意味着赋值操作后,两个对象引用同一个对象,它们指向相同的内存地址,修改其中一个对象的属性会影响到另一个对象。 class MyClass {private int intValue;private …

设计模式 六大原则之里氏替换原则

文章目录 概念替换逻辑行为不变 拆解小结 概念 子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏。 替换 替换的前提是面向对象语言所支持的多态特性,同一个行为具有多个不同表现形式或形态的能力。 逻…

Android adb shell关于CPU核的命令

Android adb shell关于CPU核的命令 先使用命令: adb shell 进入控制台。 然后,直接在$后面输入下面命令,针对CPU的命令。 cat /proc/cpuinfo | grep ^processor | wc -l 查看当前手机的CPU是几核的。 cat sys/devices/system/cpu/online …

Java面试八股之什么是Java反射

什么是Java反射 基本概念 反射是Java语言的一个重要特性,它允许我们在运行时分析类、接口、字段、方法等组件的信息,并能够动态地操作这些组件,包括创建对象、调用方法、访问和修改字段值等。简单来说,反射提供了在程序运行时对…

【kubeflow文档】kubeflow介绍与架构

1. kubeflow介绍 Kubeflow项目致力于使机器学习(ML)工作流在Kubernetes上的部署变得简单、可移植和可扩展。目标不是重新创建其他服务,而是提供一种直接的方法,将ML的开源系统部署到不同的基础设施中。无论在哪里运行Kubernetes&a…

Shell的运行原理和Linux的权限

Shell的运行原理 Linux严格意义上说是一个操作系统,我们称之为“核心(kernel)”,但我们一般用户不能直接使用kernel,而是通过kernel的“外壳程序”,也就是所谓的Shell,来与kernel沟通。 Shell…

迷茫时读书,焦虑时运动,独处时蓄力

这个观点非常富有哲理,它传达了在不同情绪状态下如何通过特定的活动来调整自己,以达到更好的心理状态和更健康的生活方式。 迷茫时读书:当我们感到迷茫、不知所措时,读书可以为我们提供新的视角、知识和启发。书籍是智慧的结晶&am…

C++ QT设计模式:责任链模式

基本概念 责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,将请求沿着处理链传递,直到有一个对象能够处理为止。 实现的模块有: Handler(处理者):定义一个处理…

Operations Research课程之非线性规划(梯度下降|牛顿法|Gurobi+Python)

目录 1.非线性规划介绍 2.梯度下降法(Gradient descent) 2.1 梯度和Hessians矩阵 2.2 梯度下降算法 2.3 算法举例 3. 牛顿法(Newton’s method) 3.1 适合单变量的牛顿法 3.2 适合多变量的牛顿法 3. 实例(GurobiPython) 3.1 Agricultural Pricing问题描述 3.2 Gurobi…

【论文复刻】堆叠柱状图+饼图

复刻了一下这篇论文里的fig2c:Impacts of COVID-19 and fiscal stimuli on global emissions and the Paris Agreement | Nature Climate Change 效果图: 主要步骤: 1. 数据准备:随机赋值 2. 图像绘制:绘制堆叠柱状…

【C++】可变参数模板简单介绍

前言 可变参数模板是C11中的新特性,它能够让我们创建可以接收可变参数的函数模板和类模板,相比C98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数是一个巨大的改进,通过系统系统推演数据的类型&#xf…

Python笔记-Alchemy中改变表的模式(库schema)

现在是2024-01-10,发到互联网上应该是2024-05-13。查了下chatgpt,麻了,乱七八糟的。 最后还是靠stackoverflow解决的,目前,从解决问题的角度来看,这个还是牛逼点。 原文如下: python - How d…

Ansible常用变量【下】

转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。 前言 在上一篇文章《Ansible常用变量【上】》中,学习了Ansible常用变量的前半部分,放了个五一假&#x…

部署的脚本

文章目录 部署脚本2024心得优秀博客 部署脚本2024 心得 脚本部署,可以帮你大大的提高工作效率。脚本也被称为自动化办公。自己写的博客要么是太简单,要么是写的不好,总之是狗屎,所以不要自己写博客。多收集和整理一些不错的博客…

拼多多流量推广和点击哪个好?拼多多自然流量规则

流量推广是通过付费广告来增加商品的曝光量,而点击推广则是通过付费广告来增加商品的点击量。那么,对于商家来说,哪种推广方式更好呢? 一、拼多多流量推广和点击哪个好 流量推广:流量推广的优势在于能够快速提高商品的曝光量&a…

买货查窜货过程中的可能情况

控价除了要管控渠道中的低价、乱价链接外,还可能需要解决窜货问题,当窜货问题蔓延不及时解决时,渠道会越来越受影响,所以治理窜货也是控价过程中很重要的一步,窜货问题的治理多通过买货溯源来解决,买货要先…

Python多线程加速-休眠部分线程

总所周知Python由于GIL的问题,使用多线程时同一时刻只有一个线程在工作。故Python会在所有线程之间不断的切换,每切换到一个线程会执行一段字节码指令然后切换到另一个线程。如果开启了很多线程,且只有小部分线程在工作,如果不休眠…