获得徽章 1
#挑战每日一条沸点#
day27
事务只能保证数据库的高可靠性,即数据库本身发生问题后,事务提交后的数据仍然能恢复;而如果不是数据库本身的故障,如硬盘损坏了,那么事务提交的数据可能就丢失了。这属于『高可用性』的范畴。因此,事务只能保证数据库的『高可靠性』,而『高可用性』需要整个系统共同配合实现。
day27
事务只能保证数据库的高可靠性,即数据库本身发生问题后,事务提交后的数据仍然能恢复;而如果不是数据库本身的故障,如硬盘损坏了,那么事务提交的数据可能就丢失了。这属于『高可用性』的范畴。因此,事务只能保证数据库的『高可靠性』,而『高可用性』需要整个系统共同配合实现。
展开
评论
点赞
#挑战每日一条沸点#
day26
按照维基百科的定义:分布式系统是一组电脑,透过网络相互连接传递消息与通信后并协调它们的行为而形成的系统。组件之间彼此进行交互以实现一个共同的目标。把需要进行大量计算的工程数据分割成小块,由多台计算机分别计算,再上传运算结果后,将结果统一合并得出数据结论的科学。
day26
按照维基百科的定义:分布式系统是一组电脑,透过网络相互连接传递消息与通信后并协调它们的行为而形成的系统。组件之间彼此进行交互以实现一个共同的目标。把需要进行大量计算的工程数据分割成小块,由多台计算机分别计算,再上传运算结果后,将结果统一合并得出数据结论的科学。
展开
评论
点赞
#挑战每日一条沸点#
day25
事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。简单地说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制。
day25
事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。简单地说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制。
展开
评论
点赞
#挑战每日一条沸点#
day24
所有的模块化都是为了满足单一设计原则 (字面意思理解即可),一个函数或者一个类再或者一个模块,职责越单一复用性就越强,同时能够间接降低耦合性
day24
所有的模块化都是为了满足单一设计原则 (字面意思理解即可),一个函数或者一个类再或者一个模块,职责越单一复用性就越强,同时能够间接降低耦合性
评论
点赞
#挑战每日一条沸点#
day23
相比传统的应用研发流程,以微服务架构为基础的研发团队更需要和依赖整体流程的敏捷属性。为了帮助更多将要或者正在以微服务为架构的项目,了解和解决诸多敏捷开发流程中的问题。
day23
相比传统的应用研发流程,以微服务架构为基础的研发团队更需要和依赖整体流程的敏捷属性。为了帮助更多将要或者正在以微服务为架构的项目,了解和解决诸多敏捷开发流程中的问题。
评论
点赞
#挑战每日一条沸点#
day22
互联网中一个项目的上线会需要各个工种间的配合,以研发为视角上会承接产品需求,下会交给测试验证,最终完成项目交付上线。其实除此之外,还会有业务、运营、UI设计、运维,来配合项目的发起、使用和运维维护。
day22
互联网中一个项目的上线会需要各个工种间的配合,以研发为视角上会承接产品需求,下会交给测试验证,最终完成项目交付上线。其实除此之外,还会有业务、运营、UI设计、运维,来配合项目的发起、使用和运维维护。
评论
点赞
#挑战每日一条沸点#
day21
职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
day21
职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
展开
评论
点赞
#每天一个知识点#
day32
golang的goroutine
Golang使用了一种称为"多路复用器"(multiplexer)的技术,可以在少量的操作系统线程上运行大量的goroutine。这种设计使得Golang能够轻松创建数千甚至数百万个goroutine,而不会导致系统资源的过度消耗。
创建一个goroutine非常简单,只需要在函数调用前加上go关键字即可。下面是一个简单的示例:
func main() {
go printHello()
fmt.Println("Main goroutine")
time.Sleep(1 * time.Second)
}
func printHello() {
fmt.Println("Hello from goroutine")
}
在上述示例中,我们使用"go"关键字启动了一个新的goroutine来执行printHello()函数。同时,主goroutine会继续执行fmt.Println("Main goroutine")。通过调用time.Sleep()函数,我们确保主goroutine在所有的goroutine执行完毕前等待1秒钟。运行该程序,你会看到两个消息同时打印出来,说明两个goroutine是并发执行的。
day32
golang的goroutine
Golang使用了一种称为"多路复用器"(multiplexer)的技术,可以在少量的操作系统线程上运行大量的goroutine。这种设计使得Golang能够轻松创建数千甚至数百万个goroutine,而不会导致系统资源的过度消耗。
创建一个goroutine非常简单,只需要在函数调用前加上go关键字即可。下面是一个简单的示例:
func main() {
go printHello()
fmt.Println("Main goroutine")
time.Sleep(1 * time.Second)
}
func printHello() {
fmt.Println("Hello from goroutine")
}
在上述示例中,我们使用"go"关键字启动了一个新的goroutine来执行printHello()函数。同时,主goroutine会继续执行fmt.Println("Main goroutine")。通过调用time.Sleep()函数,我们确保主goroutine在所有的goroutine执行完毕前等待1秒钟。运行该程序,你会看到两个消息同时打印出来,说明两个goroutine是并发执行的。
展开
评论
点赞
#挑战每日一条沸点#
day20
go generate是 Go 自带的工具。使用命令go generate执行。go generate是利用源代码中的注释工作的。格式如下:
go:generate command arg1 arg2
这样在同一个目录下执行命令go generate就会自动运行命令command arg1 arg2。command可以是在PATH中的任何命令,应用非常广泛。配合stringer命令可以为给定类型生成String方法,就可以实现我们的想法。
day20
go generate是 Go 自带的工具。使用命令go generate执行。go generate是利用源代码中的注释工作的。格式如下:
go:generate command arg1 arg2
这样在同一个目录下执行命令go generate就会自动运行命令command arg1 arg2。command可以是在PATH中的任何命令,应用非常广泛。配合stringer命令可以为给定类型生成String方法,就可以实现我们的想法。
展开
评论
点赞
#每天一个知识点#
day31
进程、线程和协程是并发编程中的概念,它们是不同层次的抽象。
进程(Process)是计算机中运行的程序的实例。每个进程都有自己的地址空间、内存和系统资源,并由操作系统进行管理。进程是程序的执行实体,它可以拥有多个线程。
线程(Thread)是进程中的执行单元,也是程序的最小执行单位。一个进程可以拥有多个线程,它们共享进程的地址空间和系统资源。线程可以独立执行,也可以协同合作完成任务。多线程可以实现并发执行,提高程序的性能和响应能力。
协程(Coroutine)是一种轻量级的线程,也被称为用户级线程。协程由编程语言或者运行时环境提供支持,可以在单个线程中实现并发和并行执行。协程可以在代码中定义和使用,而不需要像线程那样依赖于操作系统的调度和管理。协程可以通过显式地挂起和恢复来实现协作式的并发。
day31
进程、线程和协程是并发编程中的概念,它们是不同层次的抽象。
进程(Process)是计算机中运行的程序的实例。每个进程都有自己的地址空间、内存和系统资源,并由操作系统进行管理。进程是程序的执行实体,它可以拥有多个线程。
线程(Thread)是进程中的执行单元,也是程序的最小执行单位。一个进程可以拥有多个线程,它们共享进程的地址空间和系统资源。线程可以独立执行,也可以协同合作完成任务。多线程可以实现并发执行,提高程序的性能和响应能力。
协程(Coroutine)是一种轻量级的线程,也被称为用户级线程。协程由编程语言或者运行时环境提供支持,可以在单个线程中实现并发和并行执行。协程可以在代码中定义和使用,而不需要像线程那样依赖于操作系统的调度和管理。协程可以通过显式地挂起和恢复来实现协作式的并发。
展开
评论
2
#挑战每日一条沸点#
day19
Go语言解决hash冲突不是链表,实际主要用的数组(内存上的连续空间),但是并不是只使用一个数组(连续内存空间)存放键和值,而是使用了两个数组分别存储键和值
分别对应的是两个核心的结构体hmap和bmap
bmap里有两个数组分别存放key和value
day19
Go语言解决hash冲突不是链表,实际主要用的数组(内存上的连续空间),但是并不是只使用一个数组(连续内存空间)存放键和值,而是使用了两个数组分别存储键和值
分别对应的是两个核心的结构体hmap和bmap
bmap里有两个数组分别存放key和value
展开
评论
点赞
#每天一个知识点#
day30
go语言条件变量(Cond)
条件变量(Cond)是一种重要的锁机制,它允许goroutine在特定条件下等待或唤醒。条件变量常用于实现多个goroutine之间的同步和协调。Cond提供了三个方法:Wait()、Signal()和Broadcast()。Wait()用于等待条件变量的通知,当满足特定条件时,goroutine会被阻塞,直到收到通知;Signal()用于向一个等待的goroutine发送通知,唤醒其中的一个;Broadcast()用于向所有等待的goroutine发送通知,唤醒它们。
下面是一个使用条件变量的示例:
import (
"fmt"
"sync"
"time"
)
var (
data int
condition *sync.Cond
mutex sync.Mutex
)
func producer() {
time.Sleep(2 * time.Second)
mutex.Lock()
data = 10
condition.Signal() // 发送通知给等待的消费者
mutex.Unlock()
}
func consumer() {
mutex.Lock()
for data == 0 {
condition.Wait() // 等待条件变量的通知
}
fmt.Println("Consumed data:", data)
mutex.Unlock()
}
func main() {
condition = sync.NewCond(&mutex)
go producer()
go consumer()
time.Sleep(3 * time.Second)
}
day30
go语言条件变量(Cond)
条件变量(Cond)是一种重要的锁机制,它允许goroutine在特定条件下等待或唤醒。条件变量常用于实现多个goroutine之间的同步和协调。Cond提供了三个方法:Wait()、Signal()和Broadcast()。Wait()用于等待条件变量的通知,当满足特定条件时,goroutine会被阻塞,直到收到通知;Signal()用于向一个等待的goroutine发送通知,唤醒其中的一个;Broadcast()用于向所有等待的goroutine发送通知,唤醒它们。
下面是一个使用条件变量的示例:
import (
"fmt"
"sync"
"time"
)
var (
data int
condition *sync.Cond
mutex sync.Mutex
)
func producer() {
time.Sleep(2 * time.Second)
mutex.Lock()
data = 10
condition.Signal() // 发送通知给等待的消费者
mutex.Unlock()
}
func consumer() {
mutex.Lock()
for data == 0 {
condition.Wait() // 等待条件变量的通知
}
fmt.Println("Consumed data:", data)
mutex.Unlock()
}
func main() {
condition = sync.NewCond(&mutex)
go producer()
go consumer()
time.Sleep(3 * time.Second)
}
展开
评论
1
#挑战每日一条沸点#
day18
组合模式的概念:
一个具有层级关系的对象由一系列拥有父子关系的对象通过树形结构组成。
并发组合模式的概念:
一个具有层级关系的对象由一系列拥有父子关系的对象通过树形结构组成,子对象即可被串行执行,也可被并发执行
并发组合模式的优势:
原本串行的业务(存在阻塞的部分,比如网络IO等)可以被并发执行,利用多核优势提升性能。
day18
组合模式的概念:
一个具有层级关系的对象由一系列拥有父子关系的对象通过树形结构组成。
并发组合模式的概念:
一个具有层级关系的对象由一系列拥有父子关系的对象通过树形结构组成,子对象即可被串行执行,也可被并发执行
并发组合模式的优势:
原本串行的业务(存在阻塞的部分,比如网络IO等)可以被并发执行,利用多核优势提升性能。
展开
评论
点赞
#每天一个知识点#
day29
读写锁(RWMutex)
读写锁(RWMutex)是一种特殊类型的锁,它允许多个读操作同时进行,但只允许一个写操作。这种锁机制适用于读操作频繁、写操作较少的场景,可以提高程序的并发性能。RWMutex提供了三个方法:RLock()、RUnlock()和Lock()。RLock()用于获取读锁,允许多个goroutine同时获取读锁,RUnlock()用于释放读锁。Lock()用于获取写锁,只有一个goroutine可以获取写锁,其他goroutine会被阻塞,直到写锁被释放。
下面是一个使用RWMutex的示例:
import (
"fmt"
"sync"
"time"
)
var (
data map[string]string
rwMutex sync.RWMutex
)
func readData(key string) {
rwMutex.RLock()
defer rwMutex.RUnlock()
fmt.Println("Reading data:", data[key])
}
func writeData(key, value string) {
rwMutex.Lock()
defer rwMutex.Unlock()
data[key] = value
fmt.Println("Writing data:", data)
}
func main() {
data = make(map[string]string)
go writeData("key1", "value1")
go readData("key1")
go writeData("key2", "value2")
go readData("key2")
time.Sleep(1 * time.Second)
}
day29
读写锁(RWMutex)
读写锁(RWMutex)是一种特殊类型的锁,它允许多个读操作同时进行,但只允许一个写操作。这种锁机制适用于读操作频繁、写操作较少的场景,可以提高程序的并发性能。RWMutex提供了三个方法:RLock()、RUnlock()和Lock()。RLock()用于获取读锁,允许多个goroutine同时获取读锁,RUnlock()用于释放读锁。Lock()用于获取写锁,只有一个goroutine可以获取写锁,其他goroutine会被阻塞,直到写锁被释放。
下面是一个使用RWMutex的示例:
import (
"fmt"
"sync"
"time"
)
var (
data map[string]string
rwMutex sync.RWMutex
)
func readData(key string) {
rwMutex.RLock()
defer rwMutex.RUnlock()
fmt.Println("Reading data:", data[key])
}
func writeData(key, value string) {
rwMutex.Lock()
defer rwMutex.Unlock()
data[key] = value
fmt.Println("Writing data:", data)
}
func main() {
data = make(map[string]string)
go writeData("key1", "value1")
go readData("key1")
go writeData("key2", "value2")
go readData("key2")
time.Sleep(1 * time.Second)
}
展开
1
1
#挑战每日一条沸点#
day17
对于 TCP 而言,在传输的时候分为两个部分:TCP头和数据部分。
而 HTTP 类似,也是header + body的结构,具体而言: 起始行 + 头部 + 空行 + 实体
day17
对于 TCP 而言,在传输的时候分为两个部分:TCP头和数据部分。
而 HTTP 类似,也是header + body的结构,具体而言: 起始行 + 头部 + 空行 + 实体
展开
评论
点赞
#每天一个知识点#
day28
go语言中的互斥锁(Mutex)
互斥锁是一种基本的锁类型,它提供了两个重要的方法:Lock()和Unlock()。当一个线程需要访问共享资源时,它首先会调用Lock()方法来获取锁,如果锁已经被其他线程获取了,那么该线程就会被阻塞,直到锁被释放。当线程完成对共享资源的访问后,它会调用Unlock()方法来释放锁,这样其他线程就可以获取锁并进行访问。
互斥锁的使用非常简单,下面是一个使用互斥锁的示例:
import (
"fmt"
"sync"
)
var (
counter int
lock sync.Mutex
)
func increment() {
lock.Lock()
defer lock.Unlock()
counter++
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
increment()
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
}
在上面的示例中,我们定义了一个全局变量counter和一个互斥锁lock。increment()函数用于增加counter的值,它首先会获取锁,然后增加counter的值,最后释放锁。在main()函数中,我们创建了1000个goroutine来并发地调用increment()函数,确保多个线程同时对counter进行操作时的数据安全性。最后,我们使用sync.WaitGroup等待所有的goroutine执行完毕,并输出最终的counter值。
day28
go语言中的互斥锁(Mutex)
互斥锁是一种基本的锁类型,它提供了两个重要的方法:Lock()和Unlock()。当一个线程需要访问共享资源时,它首先会调用Lock()方法来获取锁,如果锁已经被其他线程获取了,那么该线程就会被阻塞,直到锁被释放。当线程完成对共享资源的访问后,它会调用Unlock()方法来释放锁,这样其他线程就可以获取锁并进行访问。
互斥锁的使用非常简单,下面是一个使用互斥锁的示例:
import (
"fmt"
"sync"
)
var (
counter int
lock sync.Mutex
)
func increment() {
lock.Lock()
defer lock.Unlock()
counter++
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
increment()
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
}
在上面的示例中,我们定义了一个全局变量counter和一个互斥锁lock。increment()函数用于增加counter的值,它首先会获取锁,然后增加counter的值,最后释放锁。在main()函数中,我们创建了1000个goroutine来并发地调用increment()函数,确保多个线程同时对counter进行操作时的数据安全性。最后,我们使用sync.WaitGroup等待所有的goroutine执行完毕,并输出最终的counter值。
展开
评论
点赞