精选Golang高频面试题和答案汇总
大家好,我是阳哥。
之前写的《 GO必知必会面试题汇总》,已经阅读破万,收藏230+。
也欢迎大家收藏、转发本文。
这篇文章给大家整理了17道Go语言高频面试题和答案详解,每道题都给出了代码示例
,方便大家更好的理解。
1.并发安全性
Go语言中的并发安全性是什么?如何确保并发安全性?
解答:
并发安全性是指在并发编程中,多个goroutine对共享资源的访问不会导致数据竞争和不确定的结果。
为了确保并发安全性,可以采取以下措施:
- 使用互斥锁(Mutex):通过使用互斥锁来保护共享资源的访问,一次只允许一个goroutine访问共享资源,从而避免竞争条件。
- 使用原子操作(Atomic Operations):对于简单的读写操作,可以使用原子操作来保证操作的原子性,避免竞争条件。
- 使用通道(Channel):通过使用通道来进行goroutine之间的通信和同步,避免共享资源的直接访问。
- 使用同步机制:使用同步机制如等待组(WaitGroup)、条件变量(Cond)等来协调多个goroutine的执行顺序和状态。
通过以上措施,可以确保并发程序的安全性,避免数据竞争和不确定的结果。
2.defer
Go语言中的defer关键字有什么作用?请给出一个使用defer的示例。
解答:
defer关键字用于延迟函数的执行,即在函数退出前执行某个操作。defer通常用于释放资源、关闭文件、解锁互斥锁等清理操作,以确保在函数执行完毕后进行处理。
也可以使用defer语句结合time包实现函数执行时间的统计。
代码示例:
下面是一个使用defer的示例,打开文件并在函数退出前关闭文件:
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("file.txt")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer func() {
err := file.Close()
if err != nil {
fmt.Println("Error closing file:", err)
}
}()
// 使用文件进行操作
// ...
fmt.Println("File operations completed")
}
在上述代码中,我们使用defer关键字延迟了文件的关闭操作,确保在函数执行完毕后关闭文件。这样可以避免忘记关闭文件而导致资源泄漏。
3.指针
面试题:Go语言中的指针有什么作用?请给出一个使用指针的示例。
解答:
指针是一种变量,存储了另一个变量的内存地址。通过指针,我们可以直接访问和修改变量的值,而不是对变量进行拷贝。
指针在传递大型数据结构和在函数间共享数据时非常有用。
代码示例
下面是一个使用指针的示例,交换两个变量的值:
package main
import "fmt"
func swap(a, b *int) {
temp := *a
*a = *b
*b = temp
}
func main() {
x := 10
y := 20
fmt.Println("Before swap:", x, y)
swap(&x, &y)
fmt.Println("After swap:", x, y)
}
在上述代码中,我们定义了一个swap函数,接收两个指针作为参数,并通过指针交换了两个变量的值。在主函数中,我们通过取地址操作符&获取变量的指针,并将指针传递给swap函数。通过使用指针,我们实现了变量值的交换。
4.map
Go语言中的map是什么?请给出一个使用map的示例。
解答:
map是一种无序的键值对集合,也称为字典。map中的键必须是唯一的,而值可以重复。map提供了快速的查找和插入操作,适用于需要根据键快速检索值的场景。
代码示例:
下面是一个使用map的示例,存储学生的成绩信息:
package main
import "fmt"
func main() {
// 创建一个map,键为学生姓名,值为对应的成绩
grades := make(map[string]int)
// 添加学生的成绩
grades["Alice"] = 90
grades["Bob"] = 85
grades["Charlie"] = 95
// 获取学生的成绩
aliceGrade := grades["Alice"]
bobGrade := grades["Bob"]
charlieGrade := grades["Charlie"]
// 打印学生的成绩
fmt.Println("Alice's grade:", aliceGrade)
fmt.Println("Bob's grade:", bobGrade)
fmt.Println("Charlie's grade:", charlieGrade)
}
在上述代码中,我们使用make函数创建了一个map,键的类型为string,值的类型为int。然后,我们通过键来添加学生的成绩信息,并通过键来获取学生的成绩。通过使用map,我们可以根据学生的姓名快速查找对应的成绩。
请注意,map是无序的,每次迭代map的顺序可能不同。
5.map的有序遍历
map是无序的,每次迭代map的顺序可能不同。如果需要按特定顺序遍历map,应该怎么做呢?
解答:
在Go语言中,map是无序的,每次迭代map的顺序可能不同。如果需要按特定顺序遍历map,可以采用以下步骤:
- 创建一个切片来保存map的键。
- 遍历map,将键存储到切片中。
- 对切片进行排序。
- 根据排序后的键顺序,遍历map并访问对应的值。
示例代码:
以下是一个示例代码,展示如何按键的升序遍历map:
package main
import (
"fmt"
"sort"
)
func main() {
m := map[string]int{
"b": 2,
"a": 1,
"c": 3,
}
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Println(k, m[k])
}
}
在上述代码中,我们创建了一个map m
,其中包含了键值对。然后,我们创建了一个切片 keys
,并遍历map将键存储到切片中。接下来,我们对切片进行排序,使用sort.Strings
函数对切片进行升序排序。最后,我们根据排序后的键顺序遍历map,并访问对应的值。
通过以上步骤,我们可以按照特定顺序遍历map,并访问对应的键值对。请注意,这里使用的是升序排序,如果需要降序排序,可以使用sort.Sort(sort.Reverse(sort.StringSlice(keys)))
进行排序。
6.切片和数组
Go语言中的slice和数组有什么区别?请给出一个使用slice的示例。
解答:
在Go语言中,数组和切片(slice)都是用于存储一组相同类型的元素。它们的区别在于长度的固定性和灵活性。数组的长度是固定的,而切片的长度是可变的。
代码示例:
下面是一个使用切片的示例,演示了如何向切片中添加元素:
package main
import "fmt"
func main() {
// 创建一个切片
numbers := []int{1, 2, 3, 4, 5}
// 向切片中添加元素
numbers = append(numbers, 6)
numbers = append(numbers, 7, 8, 9)
// 打印切片的内容
fmt.Println(numbers)
}
在上述代码中,我们使用[]int
语法创建了一个切片numbers
,并初始化了一些整数。然后,我们使用append
函数向切片中添加元素。通过使用切片,我们可以动态地添加和删除元素,而不需要事先指定切片的长度。
需要注意的是,切片是基于数组的一种封装,它提供了更便捷的操作和灵活性。切片的底层是一个指向数组的指针,它包含了切片的长度和容量信息。
以上是关于Go语言中切片和数组的区别以及使用切片的示例。切片是Go语言中常用的数据结构,它提供了更灵活的长度和操作方式,适用于动态变化的数据集合。
7.切片移除元素
怎么移除切片中的数据?
解答
要移除切片中的数据,可以使用切片的切片操作
或使用内置的append
函数来实现。以下是两种常见的方法:
1. 使用切片的切片操作:
利用切片的切片操作,可以通过指定要移除的元素的索引位置来删除切片中的数据。
例如,要移除切片中的第三个元素,可以使用切片的切片操作将切片分为两部分,并将第三个元素从中间移除。
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5}
// 移除切片中的第三个元素
indexToRemove := 2
numbers = append(numbers[:indexToRemove], numbers[indexToRemove+1:]...)
fmt.Println(numbers) // 输出: [1 2 4 5]
}
在上述代码中,我们使用切片的切片操作将切片分为两部分:numbers[:indexToRemove]
表示从开头到要移除的元素之前的部分,numbers[indexToRemove+1:]
表示从要移除的元素之后到末尾的部分。然后,我们使用append
函数将这两部分重新连接起来,从而实现了移除元素的操作。
2. 使用append
函数:
另一种方法是使用append
函数,将要移除的元素之前和之后的部分重新组合成一个新的切片。这种方法更适用于不知道要移除的元素的索引位置的情况。
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5}
// 移除切片中的元素3
elementToRemove := 3
for i := 0; i < len(numbers); i++ {
if numbers[i] == elementToRemove {
numbers = append(numbers[:i], numbers[i+1:]...)
break
}
}
fmt.Println(numbers) // 输出: [1 2 4 5]
}
在上述代码中,我们使用for
循环遍历切片,找到要移除的元素的索引位置。一旦找到匹配的元素,我们使用append
函数将要移除的元素之前和之后的部分重新连接起来,从而实现了移除元素的操作。
无论是使用切片的切片操作还是使用append
函数,都可以实现在切片中移除数据的操作。
8.panic和recover
Go语言中的panic和recover有什么作用?请给出一个使用panic和recover的示例。
解答:
panic和recover是Go语言中用于处理异常的机制。当程序遇到无法处理的错误时,可以使用panic引发一个异常,中断程序的正常执行。而recover用于捕获并处理panic引发的异常,使程序能够继续执行。
代码示例:
下面是一个使用panic和recover的示例,处理除数为零的情况:
package main
import "fmt"
func divide(a, b int) int {
defer func() {
if err := recover(); err != nil {
fmt.Println("Error:", err)
}
}()
if b == 0 {
panic("division by zero")
}
return a / b
}
func main() {
result := divide(10, 0)
fmt.Println("Result:", result)
}
执行结果如下:
Error: division by zero Result: 0
在上述代码中,我们定义了一个divide
函数,用于执行除法运算。在函数中,我们使用panic
关键字引发一个异常,当除数为零时,会引发一个"division by zero"的异常。
然后,我们使用defer
和recover
来捕获并处理这个异常,打印出错误信息。通过使用recover
,我们可以避免程序因为异常而崩溃,而是继续执行后续的代码。
9.互斥锁
什么是互斥锁(Mutex)?在Go语言中如何使用互斥锁来保护共享资源?
解答:
互斥锁是一种并发编程中常用的同步机制,用于保护共享资源的访问。
在Go语言中,可以使用sync包中的Mutex类型来实现互斥锁。通过调用Lock方法来获取锁,保护共享资源的访问,然后在使用完共享资源后调用Unlock方法释放锁。
代码示例:
package main
import (
"fmt"
"sync"
)
var (
counter int
mutex sync.Mutex
)
func increment() {
mutex.Lock()
counter++
mutex.Unlock()
}
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和一个sync.Mutex类型的互斥锁mutex。在increment函数中,我们使用mutex.Lock()获取锁,对counter进行递增操作,然后使用mutex.Unlock()释放锁。通过使用互斥锁,我们确保了对counter的并发访问的安全性。
10.自旋
解释一下并发编程中的自旋状态?
解答:
自旋状态是并发编程中的一种状态,指的是线程或进程在等待某个条件满足时,不会进入休眠或阻塞状态,而是通过不断地检查条件是否满足来进行忙等待。
在自旋状态下,线程会反复执行一个忙等待的循环,直到条件满足或达到一定的等待时间。 这种方式可以减少线程切换的开销,提高并发性能。然而,自旋状态也可能导致CPU资源的浪费,因为线程会持续占用CPU时间片,即使条件尚未满足。
自旋状态通常用于以下情况:
- 在多处理器系统中,等待某个共享资源的释放,以避免线程切换的开销。
- 在短暂的等待时间内,期望条件能够快速满足,从而避免进入阻塞状态的开销。
需要注意的是,自旋状态的使用应该谨慎,并且需要根据具体的场景和条件进行评估。如果自旋时间过长或条件不太可能很快满足,那么使用自旋状态可能会浪费大量的CPU资源。在这种情况下,更适合使用阻塞或休眠等待的方式。
总之,自旋状态是一种在等待条件满足时不进入休眠或阻塞状态的并发编程技术。它可以减少线程切换的开销,但需要权衡CPU资源的使用和等待时间的长短。
11.原子操作和锁
原子操作和锁的区别是什么?
原子操作和锁是并发编程中常用的两种同步机制,它们的区别如下:
作用范围:
- 原子操作(Atomic Operations):原子操作是一种基本的操作,可以在单个指令级别上执行,保证操作的原子性。原子操作通常用于对共享变量进行读取、写入或修改等操作,以确保操作的完整性。
- 锁(Lock):锁是一种更高级别的同步机制,用于保护临界区(Critical Section)的访问。锁可以用于限制对共享资源的并发访问,以确保线程安全。
使用方式:
- 原子操作:原子操作是通过硬件指令或特定的原子操作函数来实现的,可以直接应用于变量或内存位置,而无需额外的代码。
- 锁:锁是通过编程语言提供的锁机制来实现的,需要显式地使用锁的相关方法或语句来保护临界区的访问。
粒度:
- 原子操作:原子操作通常是针对单个变量或内存位置的操作,可以在非常细粒度的层面上实现同步。
- 锁:锁通常是针对一段代码或一组操作的访问进行同步,可以控制更大粒度的临界区。
性能开销:
- 原子操作:原子操作通常具有较低的性能开销,因为它们是在硬件级别上实现的,无需额外的同步机制。
- 锁:锁通常具有较高的性能开销,因为它们需要进行上下文切换和线程同步等操作。
综上所述,原子操作和锁是两种不同的同步机制,用于处理并发编程中的同步问题。原子操作适用于对单个变量的读写操作,具有较低的性能开销。而锁适用于对一段代码或一组操作的访问进行同步,具有更高的性能开销。选择使用原子操作还是锁取决于具体的场景和需求。
需要注意的是,原子操作通常用于对共享变量进行简单的读写操作,而锁更适用于对临界区的访问进行复杂的操作和保护。在设计并发程序时,需要根据具体的需求和性能要求来选择合适的同步机制。
12.Goroutine
Go语言中的goroutine是什么?请给出一个使用goroutine的示例。
解答:
goroutine是Go语言中轻量级的并发执行单元,可以同时执行多个goroutine,而不需要显式地管理线程的生命周期。goroutine由Go运行时(runtime)进行调度,可以在并发编程中实现并行执行。
代码示例:
下面是一个使用goroutine的示例,计算斐波那契数列:
package main
import (
"fmt"
"sync"
)
func fibonacci(n int, wg *sync.WaitGroup) {
defer wg.Done()
x, y := 0, 1
for i := 0; i < n; i++ {
fmt.Println(x)
x, y = y, x+y
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go fibonacci(10, &wg)
go fibonacci(5, &wg)
wg.Wait()
}
在上述代码中,我们使用go关键字启动了两个goroutine,分别计算斐波那契数列的前10个和前5个数字。通过使用goroutine,我们可以并行地执行这两个计算任务,而不需要显式地创建和管理线程。
13.通道
Go语言中的通道(channel)是什么?请给出一个使用通道的示例。
解答:
通道是用于在goroutine之间进行通信和同步的机制。通道提供了一种安全的、阻塞的方式来发送和接收数据。通过通道,可以实现多个goroutine之间的数据传递和同步。
代码示例:
下面是一个使用通道的示例,计算两个数的和:
package main
import "fmt"
func sum(a, b int, c chan int) {
result := a + b
c <- result // 将结果发送到通道
}
func main() {
// 创建一个整型通道
c := make(chan int)
// 启动一个goroutine来计算两个数的和
go sum(10, 20, c)
// 从通道接收结果
result := <-c
fmt.Println("Sum:", result)
}
在上述代码中,我们定义了一个sum函数,用于计算两个数的和,并将结果发送到通道c中。在main函数中,我们创建了一个整型通道c,然后启动一个goroutine来执行sum函数,并将结果发送到通道中。最后,我们通过从通道中接收结果,获取计算的和并打印出来。
通过使用通道,我们实现了goroutine之间的数据传递和同步。在示例中,通道c用于将计算结果从goroutine发送到主goroutine,实现了数据的传递和同步。
14.select
Go语言中的select语句是什么?请给出一个使用select语句的示例。
解答:
select语句是Go语言中用于处理通道操作的一种机制。它可以同时监听多个通道的读写操作,并在其中任意一个通道就绪时执行相应的操作。
代码示例:
下面是一个使用select语句的示例,从两个通道中接收数据:
package main
import "fmt"
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
ch1 <- 10
}()
go func() {
ch2 <- 20
}()
select {
case num := <-ch1:
fmt.Println("Received from ch1:", num)
case num := <-ch2:
fmt.Println("Received from ch2:", num)
}
}
在上述代码中,我们创建了两个整型通道ch1和ch2。然后,我们启动了两个goroutine,分别向通道ch1和ch2发送数据。在主goroutine中,我们使用select语句监听这两个通道的读操作,并在其中任意一个通道就绪时执行相应的操作。在示例中,我们从就绪的通道中接收数据,并打印出来。
通过使用select语句,我们可以实现对多个通道的并发操作,并根据就绪的通道执行相应的操作。这在处理并发任务时非常有用。
15.协程和通道
Go语言如何通过goroutine和channel实现并发的?请给出一个并发编程的示例。
解答:
Go语言通过goroutine和channel实现并发。goroutine是一种轻量级的线程,可以同时执行多个goroutine,而不需要显式地管理线程的生命周期。
channel是用于goroutine之间通信的管道。下面是一个简单的并发编程示例,计算斐波那契数列:
代码示例
package main
import "fmt"
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int)
go fibonacci(10, c)
for num := range c {
fmt.Println(num)
}
}
在上述代码中,我们使用goroutine启动了一个计算斐波那契数列的函数,并通过channel进行通信。主函数从channel中接收计算结果并打印。通过goroutine和channel的结合,我们实现了并发计算斐波那契数列的功能。
16.runtime
Go语言中的runtime包是用来做什么的?请给出一个使用runtime包的示例。
解答:
runtime包是Go语言的运行时系统,提供了与底层系统交互和控制的功能。它包含了与内存管理、垃圾回收、协程调度等相关的函数和变量。
代码示例:
下面是一个使用runtime包的示例,获取当前goroutine的数量:
package main
import (
"fmt"
"runtime"
)
func main() {
num := runtime.NumGoroutine()
fmt.Println("Number of goroutines:", num)
}
17.垃圾回收
Go语言中的垃圾回收是如何工作的?请给出一个使用垃圾回收的示例。
解答:
Go语言中的垃圾回收器(Garbage Collector)是自动管理内存的机制,用于回收不再使用的内存。垃圾回收器会自动检测不再使用的对象,并释放其占用的内存空间。
代码示例
下面是一个使用垃圾回收的示例,创建一个大量的临时对象:
package main
import (
"fmt"
"runtime"
"time"
)
func createObjects() {
for i := 0; i < 1000000; i++ {
_ = make([]byte, 1024)
}
}
func main() {
createObjects()
time.Sleep(time.Second) // 等待垃圾回收器执行
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Println("Allocated memory:", stats.Alloc)
}
打印结果:
Allocated memory: 77344
在上述代码中,我们通过循环创建了大量的临时对象。然后,我们使用time.Sleep
函数等待垃圾回收器执行。最后,我们使用runtime.ReadMemStats
函数读取内存统计信息,并打印出已分配的内存大小。
通过使用垃圾回收器,我们可以自动管理内存,避免手动释放不再使用的对象。垃圾回收器会在适当的时机自动回收不再使用的内存,从而提高程序的性能和可靠性。
总结
我们在回答面试题的时候,不能干巴巴的去背八股文,一定要结合应用场景,最好能结合过去做过的项目,去和面试官沟通。
这些场景题虽然不要求我们手撕代码,但是解决思路和关键方法还是要烂熟于心的。
这篇文章不仅给出了常见的面试题和答案,并且给出了这些知识点的应用场景、也给出了解决这些问题的思路,并且结合这些思路提供了关键代码。这些代码段都是可以直接CV到本地运行起来的,并且都写清楚了注释,欢迎大家动起手来操练起来,不要死记硬背八股文。
最后,整理不易,原创更不易,你的点赞、留言、转发是对我最大的支持!
全网搜索:王中阳Go
,获得更多面试题资料。
精选Golang高频面试题和答案汇总的更多相关文章
- 最常见的Java面试题及答案汇总(三)
上一篇:最常见的Java面试题及答案汇总(二) 多线程 35. 并行和并发有什么区别? 并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔发生. 并行是在不同实体上的多个事 ...
- 最常见的Java面试题及答案汇总(二)
上一篇:最常见的Java面试题及答案汇总(一) 容器 18. java 容器都有哪些? 常用容器的图录: 19. Collection 和 Collections 有什么区别? java.util.C ...
- Python面试题及答案汇总整理(2019版)
发现网上很多Python面试题都没有答案,所以博主花了很长时间搜集整理了这套Python面试题及答案,由于网上的Python相关面试题大多数都是2019年的,所以我这个也是2019版的,哈哈~ (文末 ...
- 精选Hive高频面试题11道,附答案详细解析(好文收藏)
1. hive内部表和外部表的区别 未被external修饰的是内部表,被external修饰的为外部表. 区别: 内部表数据由Hive自身管理,外部表数据由HDFS管理: 内部表数据存储的位置是hi ...
- BAT面试笔试33题:JavaList、Java Map等经典面试题!答案汇总!
JavaList面试题汇总 1.List集合:ArrayList.LinkedList.Vector等. 2.Vector是List接口下线程安全的集合. 3.List是有序的. 4.ArrayLis ...
- 最常见的Java面试题及答案汇总(六)
异常 74. throw 和 throws 的区别? throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是 ...
- Java面试题及答案汇总(一)
Java 基础 1. JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Ru ...
- 最常见的Java面试题及答案汇总(一)
Java 基础部分 1. JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java ...
- Java基础学习总结(74)——Java常见笔试题及答案汇总
1. 下面哪些是合法的标识符?(ABE )--标识符 A. $persons B. TwoUsers C. *point D. this E. _endline 2. 下面程序运行的结果是( D )- ...
- 最常见的Java面试题及答案汇总(五)
Java Web 64. jsp 和 servlet 有什么区别? jsp经编译后就变成了Servlet.(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器 ...
随机推荐
- 京东LBS推荐算法实践
作者:京东零售 郑书剑 1.推荐LBS业务介绍 1.1 业务场景 现有的同城购业务围绕京东即时零售能力搭建了到店.到家两种业务场景.同城业务与现有业务进行互补,利用高频,时效性快的特点,可以有效提升主 ...
- [Linux]Filesystem Hierarchy Standard/文件系统层次结构标准(FHS for Linux)
1 文件系统层次结构标准 本篇文章为维基百科中关于FHS的译文,原文见 wiki:https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard ...
- Unity学习笔记02 —— C#语法
C#语法 控制台 Console Console.WriteLine(); Console.ReadLine(); 随机数 Random Random random = new Random(); r ...
- Vue上传XLS文件
data() { return { tableData:[] } }, //原生JS+XLSX包实现 xls文件上传 methods: { //上传excel表格文件 uploadHandler(da ...
- DyLoRA:使用动态无搜索低秩适应的预训练模型的参数有效微调
又一个针对LoRA的改进方法: DyLoRA: Parameter-Efficient Tuning of Pretrained Models using Dynamic Search-Free Lo ...
- GraalVM(云原生时代的Java)和IoT在边缘侧落地与实践
环顾四周,皆是对手! 云时代的掉队者,由于Java启动的高延时.对资源的高占用.导致在Serverless及FaaS架构下力不从心,在越来越流行的边缘计算.IoT方向上也是难觅踪影; Java语言在业 ...
- 数据分析02-(pandas介绍、jupyter notebook)
数据分析-02 数据分析-02 pandas pandas介绍 pandas核心数据结构 Series DataFrame 核心数据结构操作 复合索引 Jupyter notebook 数据加载 处理 ...
- 一文吃透Tomcat核心知识点
架构 首先,看一下整个架构图.最全面的Java面试网站 接下来简单解释一下. Server:服务器.Tomcat 就是一个 Server 服务器. Service:在服务器中可以有多个 Service ...
- 各种远程工具通过ssh连接服务器
开头 最近遇到一个新的连接方式,不能使用日常的本地通过账号连接,要通过私钥和公钥的连接方式,然后连接到服务器之后才能连接到数据库.因为之前没试过这种连接方式,所以很多工具有不同的连接方式.所以现在就记 ...
- 音视频八股文(7)-- 音频aac adts三层结构
AAC介绍 AAC(Advanced Audio Coding)是一种现代的音频编码技术,用于数字音频的传输和存储领域.AAC是MPEG-2和MPEG-4标准中的一部分,可提供更高质量的音频数据,并且 ...