参考技术A
不同于传统的多线程并发模型使用共享内存来实现线程间通信的方式,golang 的哲学是通过 channel 进行协程(goroutine)之间的通信来实现数据共享。这种方式的优点是通过提供原子的通信原语,避免了竞态情形(race condition)下复杂的锁机制。
channel 可以看成一个 FIFO 队列,对 FIFO 队列的读写都是原子的操作,不需要加锁。对 channel 的操作行为结果总结如下:
读取一个已关闭的 channel 时,总是能读取到对应类型的零值,为了和读取非空未关闭 channel 的行为区别,可以使用两个接收值:
golang 中大部分类型都是值类型(只有 slice / channel / map 是引用类型),读/写类型是值类型的 channel 时, 如果元素 size 比较大时,应该使用指针代替,避免频繁的内存拷贝开销 。
main方法里创建了一个string类型的Channel,实现主协程与子协程 go SendMessage 进行通信。主协程执行到 <-values 时发生阻塞,等待读取 values Channel的值,而子协程执行 SendMessage 方法时写入 values Channel。即,主协程发生阻塞,等待子协程执行完毕后再继续执行。
执行的结果如下:
从日志可以看出,打印val语句必须在子协程 go SendMessage 执行完成后才执行。
如果在此基础上添加多一个协程写入 values Channel会发生什么?
在主协程中,启动两个子协程给Channel写数据。而在 SendMessage 方法里,为了达到显示效果,在写入Channel前先睡眠1秒,在主协程也添加睡眠时间。
执行日志打印如下:
发现只有其中一个协程完成写入Channel的操作。因为此Channel没有设置缓存,所有只能保存一个写入值。
那么如何才能保证两个子协程能正常写入Channel呢?
为了保证上面的两个子协程能顺利地把值写入Channel,我们创建一个带缓冲的Channel。
新创建的Channel缓冲两个值,这样就能保证两个子协程能正常写入到Channel中。下面看看打印日志:
如我们猜想一样,两个子协程都能顺利结束。
晚安~
生产者
import pika
#coding=utf8
credentials = pika.PlainCredentials(‘guest‘, ‘密码‘)
connection = pika.BlockingConnection(pika.ConnectionParameters(‘IP‘,5672,‘/‘,credentials))
channel = connection.channel()
channel.queue_declare(queue=‘hello‘)
channel.basic_publish(exchange=‘‘,
routing_key=‘hello‘,
body=‘rabbitmq test!‘)
print("开始队列")
connection.close()
消费者
import pika
#coding=utf8
credentials = pika.PlainCredentials(‘guest‘, ‘密码‘)
connection = pika.BlockingConnection(pika.ConnectionParameters(‘IP‘,5672,‘/‘,credentials))
channel = connection.channel()
# rabbitmq消费端仍然使用此方法创建队列。这样做的意思是:若是没有就创建。和发送端道理道理。目的是为了保证队列一定会有
channel.queue_declare(queue=‘hello‘)
# 收到消息后的回调
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
channel.basic_consume(callback, queue=‘hello‘, no_ack=True)
print(‘ [*] Waiting for messages.‘)
channel.start_consuming()