go笔记记录——channel

channel有什么特点

channel有2种类型:无缓冲、有缓冲

channel有3种模式:写操作模式(单向通道)、读操作模式(单向通道)、读写操作模式(双向通道)

在这里插入图片描述

channel有3种状态:未初始化、正常、关闭

在这里插入图片描述

注意点:

1.一个channel不能多次关闭,会导致painc

2.如果多个goroutine都监听同一个channel,那么 channel 上的数据都可能随机被某一个goroutine取走进行消费

3.如果多个goroutine监听同一个channel,如果这个channel被关闭,则所有goroutine都能收到退出信号


channel的底层实现原理

概念:

Go中的channel是一个队列,遵循先进先出的原则,负责协程之间的通信(Go语言提倡不要通过共享内存来通信,而要通过通信来实现内存共享,CSP(CommunicatingSequentiall Process)并发模型,就是通过goroutine和channel来实现的)

使用场景

停止信号监听

定时任务

生产方和消费方解耦

控制并发数

底层数据结构:
通过var声明或者make函数创建的channel变量是一个存储在函数栈帧上的指针,占用8个字节,指向堆上的hchan结构体

在这里插入图片描述
为什么用循环数组:用循环数组后我们就消费元素的时候不需要删除了,只需要记住我们的数组下标就ok

等待队列:

双向链表,包含一个头结点和一个尾结点

每个节点是一个sudog结构体变量,记录哪个协程在等待,等待的是哪个channel,等待发送/接收的数据在哪里

在这里插入图片描述

总结hchan结构体的主要组成部分有四个:
1.用来保存goroutine之间传递数据的循环数组:buf
2.用来记录此循环数组当前发送或接收数据的下标值:sendx和recvx
3.用于保存向该chan发送和从该chan接收数据被阻塞的goroutine队列: sendq和recvq
4.保证channel写入和读取数据时线程安全的锁:lock


有缓存channel和无缓存channel的区别

无缓冲:一个送信人去你家送信,你不在家他不走,你一定要接下信,他才会走。

有缓冲:一个送信人去你家送信,扔到你家的信箱转身就走,除非你的信箱满了,他必须等信箱有多余空间才会走。

在这里插入图片描述

无缓存的channel有发送者必须有接收者,否则会报错,发生阻塞


channel为什么是线程安全

为什么设计成线程安全?
不同协程通过channel进行递信,本身的使用场景就是多线程,为了保证数据的一致性,必须实现线程安全

如何实现线程安全的?
channel的底层实现中, hchan结构体中采用Mutex锁来保证数据读写安全。在对循环数组buf中的数据进行入队和出队操作时,必须先获取互斥锁,才能操作chrnel数据


channel如何控制groutine并发执行顺序

多个goroutine并发执行时,每一个goroutine抢到处理器的时间点不一致,gorouine的执行本身不能保证顺序。"即代码中先写的gorouine并不能保证先执行

思路:使用channel进行通信通知,用channel去传递信息,从而控制并发执行顺序

在这里插入图片描述

输出:
groutine1
groutine2
groutine3
duration:1//证明了我们是并行的,否则应该是三秒


channel的共享内存有什么优劣?

大部分语言通过共享内存来通信,go是通过通信来共享内存(csp)

优点:
帮助解耦生产者和消费者
缺点:
容易出现死锁


channel什么时候容易死锁

死锁:
1.单个协程永久阻塞
2.两个或两个以上的协程的执行过程中,由于竞争资源或由于彼此通信而造成的一种阻塞的现象。

channel死锁场景:

1.非缓存channel只写不读

2.非缓存channel读在写后面

3.缓存channel写入超过缓冲区数量

4.空读

  1. 多个协程互相等待

创建,发送,接受,关闭

创建

//带缓冲
ch := make( chan int,3)
//不带缓冲
ch := make(chan int)

创建时会做一些检查:
·元素大小不能超过64K ·
元素的对齐大小不能超过maxAlign也就是8字节。
计算出来的内存是否超过限制

创建时的策略:
如果是无缓冲的channel,会直接给hchan分配内存 ·
如果是有缓冲的channel,并且元素不包含指针,那么会为hchan和底层数组分配一段连续的地址·
如果是有缓冲的channel,并且元素包含指针,那么会为hchan和底层数组分别分配地址

发送

阻塞式:
调用chansend函数,并且block=true

ch <- 10

非阻塞式:
调用chansend函数,并且block=false

select {
case ch c<-10:
...
default
}

向channel中发送数据时大概分为两大块:检查和数据发送,数据发送流程如下

1.如果channel的读等待队列存在接收者goroutine
。将数据直接发送给第一个等待的goroutine,唤醒接收的goroutine

2.如果channel的读等待队列不存在接收者goroutine
。如果循环数组buf未满,那么将会把数据发送到循环数组buf的队尾
。如果循环数组buf已满,这个时候就会走阻塞发送的流程,将当前goroutine加入写等待队列,并挂起等待唤醒

接收

阻塞式四种:
在这里插入图片描述

非阻塞式:

在这里插入图片描述

向channel中接收数据时大概分为两大块,检查和数据发送,而数据接收流程如下:

1.如果channel的写等待队列存在发送者goroutine

。如果是无缓冲channel,直接从第一个发送者goroutine那里把数据拷贝给接收变量,唤醒发送的goroutine

。如果是有缓冲channel(已满),将循环数组buf的队首元素拷贝给接收变量,将第一个发送者goroutine的数据拷贝到buf循环数组队尾,唤醒发送的goroutine

2.如果channel的写等待队列不存在发送者goroutine:

。如果循环数组buf非空,将循环数组buf的队首元素拷贝给接收变量

。如果循环数组buf为空,这个时候就会走阻塞接收的流程,将当前goroutine加入读等待队列,并挂起等待唤醒

关闭

close(ch)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,下面是SparkSQL代码笔记03——连接Hive的中文回复: 在SparkSQL中,我们可以通过以下步骤连接Hive: 1. 首先,需要在SparkSession中启用Hive支持,可以使用以下代码: ``` from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("SparkSQL Hive Example") \ .config("spark.sql.warehouse.dir", "/user/hive/warehouse") \ .enableHiveSupport() \ .getOrCreate() ``` 其中,`enableHiveSupport()`方法启用了Hive支持,`config("spark.sql.warehouse.dir", "/user/hive/warehouse")`指定了Hive元数据存储的目录。 2. 接下来,我们可以使用`spark.sql()`方法执行Hive SQL语句,例如: ``` spark.sql("show databases").show() ``` 这将显示所有的Hive数据库。 3. 如果需要在SparkSQL中访问Hive表,可以使用以下代码: ``` df = spark.sql("select * from my_hive_table") ``` 其中,`my_hive_table`是Hive中的表名。 4. 如果需要在SparkSQL中创建Hive表,可以使用以下代码: ``` spark.sql("create table my_hive_table (id int, name string)") ``` 这将在Hive中创建一个名为`my_hive_table`的表,包含两个列:`id`和`name`。 以上就是连接Hive的基本步骤。需要注意的是,连接Hive需要在Spark集群中安装Hive,并且需要将Hive的JAR包添加到Spark的CLASSPATH中。 ### 回答2: SparkSQL是Apache Spark的一个组件,它提供了用于分布式数据处理的高级SQL查询引擎。SparkSQL支持连接多种数据源,其中之一就是Hive。 如何连接Hive? 在开始连接Hive之前,我们需要确保Hadoop和Hive的配置已经被正确的设置好了,以便Spark能够访问Hive元数据和数据。 首先,我们需要在Spark环境中添加Hive支持。运行下面的代码: `from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("hive_support") \ .enableHiveSupport() \ .getOrCreate()` 其中,`.enableHiveSupport()`将启用hive支持。 接下来,我们可以使用SparkSession连接Hive。运行下面的代码: `hive_df = spark.sql("SELECT * FROM default.student")` 其中,“default”是Hive的默认数据库,“student”是Hive数据库中的表名。 如果你要访问非默认的Hive数据库,可以使用下面的代码: `hive_df = spark.sql("SELECT * FROM dbname.student")` 其中,“dbname”是非默认的Hive数据库名。 我们还可以使用HiveContext来连接Hive。运行下面的代码: `from pyspark.sql import HiveContext hive_context = HiveContext(sc)` 其中,“sc”是SparkContext对象。 我们可以像这样从Hive中检索数据: `hive_df = hive_ctx.sql("SELECT * FROM default.student")` 现在你已经成功地连接Hive并从中检索了数据,你可以使用SparkSQL的强大功能对数据进行分析。而在连接Hive之外,在SparkSQL中还可以连接其他数据源,包括MySQL、PostgreSQL、Oracle等。 ### 回答3: Spark SQL是一个强大的分布式计算引擎,它可以支持处理多种数据源,并可通过Spark SQL shell、Spark应用程序或JDBC/ODBC接口等方式进行操作。其中,连接Hive是Spark SQL最常用的数据源之一。下面,将介绍如何通过Spark SQL连接Hive。 1、在Spark配置中设置Hive Support 要连接Hive,首先需要在Spark配置中开启Hive Support。在启动Spark Shell时,可以添加如下参数: ``` ./bin/spark-shell --master local \ --conf spark.sql.warehouse.dir="/user/hive/warehouse" \ --conf spark.sql.catalogImplementation=hive \ --conf spark.sql.hive.metastore.version=0.13 \ --conf spark.sql.hive.metastore.jars=maven ``` 这里以本地模式为例,设置Spark SQL的元数据存储在本地文件系统中,设置Hive为catalog实现,以及为Hive Metastore设置版本和JAR文件路径。根据实际情况,还可以指定其他参数,如Hive Metastore地址、数据库名称、用户名和密码等。 2、创建SparkSession对象 在连接Hive之前,需要先创建SparkSession对象。可以通过调用SparkSession.builder()静态方法来构建SparkSession对象,如下所示: ``` val spark = SparkSession.builder() .appName("SparkSQLTest") .config("spark.sql.warehouse.dir", "/user/hive/warehouse") .enableHiveSupport() .getOrCreate() ``` 这里通过builder()方法指定应用程序名称、元数据存储路径以及启用Hive Support,最后调用getOrCreate()方法创建SparkSession对象。 3、通过Spark SQL操作Hive表 通过Spark SQL连接Hive后,就可以通过Spark SQL语句来操作Hive表了。例如,我们可以使用select语句查询Hive表中的数据: ``` val df = spark.sql("SELECT * FROM tablename") df.show() ``` 其中,select语句指定要查询的列和表名,然后通过show()方法来显示查询结果。 除了查询数据之外,Spark SQL还可以通过insertInto语句将数据插入到Hive表中: ``` val data = Seq(("Alice", 25), ("Bob", 30)) val rdd = spark.sparkContext.parallelize(data) val df = rdd.toDF("name", "age") df.write.mode(SaveMode.Append).insertInto("tablename") ``` 这里先创建一个包含数据的RDD对象,然后将其转换为DataFrame对象,并指定列名。接着,通过insertInto()方法将DataFrame对象中的数据插入到Hive表中。 总之,通过Spark SQL连接Hive可以方便地查询、插入、更新和删除Hive表中的数据,从而实现更加灵活和高效的数据处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值