第二篇

118 阅读3分钟

实现思路:

  1. 创建一个帖子结构体,包含帖子的标题、内容、作者等信息。
  2. 使用sync.Mutexsync.RWMutex来保证帖子ID生成和索引更新的并发安全。
  3. 使用map来存储帖子,以ID为键,帖子结构体为值,用于快速根据ID查找帖子。
  4. 使用一个文件来记录已经分配的ID,每次生成新的ID时,先读取该文件中最后一个ID,并在此基础上递增。
  5. 使用文件追加的方式,将新发布的帖子信息记录到一个文件中,实现数据的持久化存储。

代码:

package main

import (
	"fmt"
	"os"
	"sync"
)

// 帖子结构体
type Post struct {
	ID      int
	Title   string
	Content string
	Author  string
}

// 社区结构体
type Community struct {
	Posts       map[int]*Post
	indexFile   *os.File
	lastPostID  int
	idMutex     sync.Mutex // 用于保证ID生成的并发安全性
	mapMutex    sync.RWMutex // 用于保证map的并发安全性
}

// 创建一个新的帖子
func (c *Community) CreatePost(title, content, author string) *Post {
	c.idMutex.Lock()
	defer c.idMutex.Unlock()

	// 读取最后一个ID
	c.lastPostID++
	post := &Post{
		ID:      c.lastPostID,
		Title:   title,
		Content: content,
		Author:  author,
	}

	// 写入新的ID到文件
	c.indexFile.Seek(0, 0) // 将文件指针定位到开头
	fmt.Fprintf(c.indexFile, "%d", c.lastPostID)

	c.mapMutex.Lock()
	defer c.mapMutex.Unlock()

	// 将帖子添加到map中
	c.Posts[c.lastPostID] = post

	return post
}

// 初始化社区
func NewCommunity(indexFilePath string) (*Community, error) {
	indexFile, err := os.OpenFile(indexFilePath, os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return nil, err
	}

	// 读取最后一个ID
	var lastID int
	fmt.Fscanf(indexFile, "%d", &lastID)

	return &Community{
		Posts:      make(map[int]*Post),
		indexFile:  indexFile,
		lastPostID: lastID,
	}, nil
}

func main() {
	// 初始化社区
	community, err := NewCommunity("index.txt")
	if err != nil {
		fmt.Println("社区初始化失败:", err)
		return
	}
	defer community.indexFile.Close()

	// 创建新的帖子
	post1 := community.CreatePost("标题1", "内容1", "作者1")
	post2 := community.CreatePost("标题2", "内容2", "作者2")

	// 查询帖子
	community.mapMutex.RLock()
	post, ok := community.Posts[post1.ID]
	community.mapMutex.RUnlock()
	if ok {
		fmt.Println("查询到帖子:", post)
	} else {
		fmt.Println("未找到帖子。")
	}
}

路径记录:

  1. 创建一个新文件夹,命名为community
  2. 在该文件夹下创建main.go文件,复制上述代码到main.go中。
  3. community文件夹下创建一个名为index.txt的空文件,用于记录最后一个ID。
  4. 打开命令行终端,进入community文件夹路径。
  5. 使用go run main.go命令运行程序。

总结:

首先,我们定义了一个帖子结构体,用于存储帖子的信息,包括ID、标题、内容和作者等字段。然后,我们设计了一个社区结构体,其中包含了一个map用于存储帖子信息,一个用于记录ID的文件指针,以及用于保护ID生成的互斥锁。通过这样的数据结构,我们能够方便地管理和查找帖子,同时保证了ID的唯一性和并发安全性。

接着,我们实现了创建新帖子的方法CreatePost。在该方法中,我们通过互斥锁保护ID生成的操作,读取并递增最后一个ID,并将新的ID写入文件中。然后,创建新的帖子并将其添加到map中,确保了唯一性和并发安全性。通过这个方法,用户可以方便地发布新的帖子,并且无需担心ID的冲突问题。

为了实现数据的持久化存储,我们使用了文件操作。通过os.OpenFile打开文件,使用Fprintf向文件写入新的ID,保证每次写入都在文件的开头。这样,即使程序退出,数据仍然可以保存在文件中,下次启动时可以继续使用,实现了数据的持久化。

同时,我们使用sync.RWMutex保护map在并发情况下的读写操作,避免数据竞争问题。在创建新帖子和查询帖子信息时,我们使用了RWMutex的读锁保护,允许多个协程同时读取数据。而在更新map和写入ID到文件时,我们使用了RWMutex的写锁保护,确保在写操作期间其他协程无法读取或写入数据,保证了数据的一致性和完整性。

通过NewCommunity函数初始化社区,读取ID文件中的最后一个ID,并将其赋值给社区结构体,确保了ID的连续性。在程序结束时,通过defer机制来关闭文件,确保资源的正确释放。