python對(duì)RabbitMQ的簡(jiǎn)單入門(mén)使用教程
(一)RabbitMQ的簡(jiǎn)介
RabbitMq 是實(shí)現(xiàn)了高級(jí)消息隊(duì)列協(xié)議(AMQP)的開(kāi)源消息代理中間件。消息隊(duì)列是一種應(yīng)用程序?qū)?yīng)用程序的通行方式,應(yīng)用程序通過(guò)寫(xiě)消息,將消息傳遞于隊(duì)列,由另一應(yīng)用程序讀取 完成通信。而作為中間件的 RabbitMq 無(wú)疑是目前最流行的消息隊(duì)列之一。目前使用較多的消息隊(duì)列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ。
RabbitMQ總體架構(gòu)
PS:生產(chǎn)者和消費(fèi)者可能在不同的程序或主機(jī)中,當(dāng)然也有可能一個(gè)程序有可能既是生產(chǎn)者,也是消費(fèi)者。
RabbitMq 應(yīng)用場(chǎng)景廣泛:
1.系統(tǒng)的高可用:日常生活當(dāng)中各種商城秒殺,高流量,高并發(fā)的場(chǎng)景。當(dāng)服務(wù)器接收到如此大量請(qǐng)求處理業(yè)務(wù)時(shí),有宕機(jī)的風(fēng)險(xiǎn)。某些業(yè)務(wù)可能極其復(fù)雜,但這部分不是高時(shí)效性,不需要立即反饋給用戶(hù),我們可以將這部分處理請(qǐng)求拋給隊(duì)列,讓程序后置去處理,減輕服務(wù)器在高并發(fā)場(chǎng)景下的壓力。
2.分布式系統(tǒng),集成系統(tǒng),子系統(tǒng)之間的對(duì)接,以及架構(gòu)設(shè)計(jì)中常常需要考慮消息隊(duì)列的應(yīng)用。
(二)RabbitMQ的安裝
apt-get update apt-get install erlang apt-get install rabbitmq-server #啟動(dòng)rabbitmq: service rabbitmq-server start #停止rabbitmq: service rabbitmq-server stop #重啟rabbitmq: service rabbitmq-server restart #啟動(dòng)rabbitmq插件:rabbitmq-plugins enable rabbitmq_management
啟用rabbitmq_management插件后就可以登錄后臺(tái)管理頁(yè)面了,瀏覽器輸入ip:15672
自帶的密碼和用戶(hù)名都是guest,但是只能本機(jī)登錄
所以下面我們添加新用戶(hù),和自定義權(quán)限
#添加新用戶(hù) rabbitmqctl add_user 用戶(hù)名 密碼 #給指定用戶(hù)添加管理員權(quán)限 rabbitmqctl set_user_tags 用戶(hù)名 administrator 給用戶(hù)添加權(quán)限 rabbitmqctl set_permissions -p / 用戶(hù)名 ".*" ".*" ".*"
在web頁(yè)面輸入用戶(hù)名,和密碼
(三)python操作RabbitMQ
python中使用pika操作RabbitMQ
pip install pika #皮卡皮卡,哈哈
(四)RabbitMQ簡(jiǎn)單模式
上代碼
# coding=utf-8 ### 生產(chǎn)者 import pika import time user_info = pika.PlainCredentials('root', 'root')#用戶(hù)名和密碼 connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info))#連接服務(wù)器上的RabbitMQ服務(wù) # 創(chuàng)建一個(gè)channel channel = connection.channel() # 如果指定的queue不存在,則會(huì)創(chuàng)建一個(gè)queue,如果已經(jīng)存在 則不會(huì)做其他動(dòng)作,官方推薦,每次使用時(shí)都可以加上這句 channel.queue_declare(queue='hello') for i in range(0, 100): channel.basic_publish(exchange='',#當(dāng)前是一個(gè)簡(jiǎn)單模式,所以這里設(shè)置為空字符串就可以了 routing_key='hello',# 指定消息要發(fā)送到哪個(gè)queue body='{}'.format(i)# 指定要發(fā)送的消息 ) time.sleep(1) # 關(guān)閉連接 # connection.close()
PS:RabbitMQ中所有的消息都要先通過(guò)交換機(jī),空字符串表示使用默認(rèn)的交換機(jī)
# coding=utf-8 ### 消費(fèi)者 import pika user_info = pika.PlainCredentials('root', 'root') connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) channel = connection.channel() # 如果指定的queue不存在,則會(huì)創(chuàng)建一個(gè)queue,如果已經(jīng)存在 則不會(huì)做其他動(dòng)作,生產(chǎn)者和消費(fèi)者都做這一步的好處是 # 這樣生產(chǎn)者和消費(fèi)者就沒(méi)有必要的先后啟動(dòng)順序了 channel.queue_declare(queue='hello') # 回調(diào)函數(shù) def callback(ch, method, properties, body): print('消費(fèi)者收到:{}'.format(body)) # channel: 包含channel的一切屬性和方法 # method: 包含 consumer_tag, delivery_tag, exchange, redelivered, routing_key # properties: basic_publish 通過(guò) properties 傳入的參數(shù) # body: basic_publish發(fā)送的消息 channel.basic_consume(queue='hello', # 接收指定queue的消息 auto_ack=True, # 指定為T(mén)rue,表示消息接收到后自動(dòng)給消息發(fā)送方回復(fù)確認(rèn),已收到消息 on_message_callback=callback # 設(shè)置收到消息的回調(diào)函數(shù) ) print('Waiting for messages. To exit press CTRL+C') # 一直處于等待接收消息的狀態(tài),如果沒(méi)收到消息就一直處于阻塞狀態(tài),收到消息就調(diào)用上面的回調(diào)函數(shù) channel.start_consuming()
對(duì)于上面的這種模式,有一下兩個(gè)不好的地方:
一個(gè)是在我們的消費(fèi)者還沒(méi)開(kāi)始消費(fèi)完隊(duì)列里的消息,如果這時(shí)rabbitmq服務(wù)掛了,那么消息隊(duì)列里的消息將會(huì)全部丟失,解決方法是在聲明隊(duì)列時(shí),聲明隊(duì)列為可持久化存儲(chǔ)隊(duì)列,并且在生產(chǎn)者在將消息插入到消息隊(duì)列時(shí),設(shè)置消息持久化存儲(chǔ),具體如下
# coding=utf-8 ### 生產(chǎn)者 import pika import time user_info = pika.PlainCredentials('root', 'root') connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) # 創(chuàng)建一個(gè)channel channel = connection.channel() # 如果指定的queue不存在,則會(huì)創(chuàng)建一個(gè)queue,如果已經(jīng)存在 則不會(huì)做其他動(dòng)作,官方推薦,每次使用時(shí)都可以加上這句 channel.queue_declare(queue='durable_queue',durable=True) #PS:這里不同種隊(duì)列不允許名字相同 for i in range(0, 100): channel.basic_publish(exchange='', routing_key='durable_queue', body='{}'.format(i), properties=pika.BasicProperties(delivery_mode=2) ) # 關(guān)閉連接 # connection.close()
消費(fèi)者與上面的消費(fèi)者沒(méi)有什么不同,具體的就是消費(fèi)聲明的隊(duì)列,也要是可持久化的隊(duì)列,還有就是,即使在生產(chǎn)者插入消息時(shí),設(shè)置當(dāng)前消息持久化存儲(chǔ)(properties=pika.BasicProperties(delivery_mode=2)),并不能百分百保證消息真的被持久化,因?yàn)镽abbitMQ掛掉的時(shí)候它可能還保存在緩存中,沒(méi)來(lái)得及同步到磁盤(pán)中
在生產(chǎn)者插入消息后,立刻停止rabbitmq,并重新啟動(dòng),其實(shí)我們?cè)趙eb管理頁(yè)面也可看到未被消費(fèi)的信息,當(dāng)然在啟動(dòng)消費(fèi)者后也成功接收到了消息
上面說(shuō)的第二點(diǎn)不好就是,如果在消費(fèi)者獲取到隊(duì)列里的消息后,在回調(diào)函數(shù)的處理過(guò)程中,消費(fèi)者突然出錯(cuò)或程序崩潰等異常,那么就會(huì)造成這條消息并未被實(shí)際正常的處理掉。為了解決這個(gè)問(wèn)題,我們只需在消費(fèi)者basic_consume(auto_ack=False),并在回調(diào)函數(shù)中設(shè)置手動(dòng)應(yīng)答即可ch.basic_ack(delivery_tag=method.delivery_tag),具體如下
# coding=utf-8 ### 消費(fèi)者 import pika import time user_info = pika.PlainCredentials('root', 'root') connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) channel = connection.channel() # 如果指定的queue不存在,則會(huì)創(chuàng)建一個(gè)queue,如果已經(jīng)存在 則不會(huì)做其他動(dòng)作,生產(chǎn)者和消費(fèi)者都做這一步的好處是 # 這樣生產(chǎn)者和消費(fèi)者就沒(méi)有必要的先后啟動(dòng)順序了 channel.queue_declare(queue='queue') # 回調(diào)函數(shù) def callback(ch, method, properties, body): time.sleep(5) ch.basic_ack(delivery_tag=method.delivery_tag) print('消費(fèi)者收到:{}'.format(body.decode('utf-8'))) # channel: 包含channel的一切屬性和方法 # method: 包含 consumer_tag, delivery_tag, exchange, redelivered, routing_key # properties: basic_publish 通過(guò) properties 傳入的參數(shù) # body: basic_publish發(fā)送的消息 channel.basic_consume(queue='queue', # 接收指定queue的消息 auto_ack=False, # 指定為False,表示取消自動(dòng)應(yīng)答,交由回調(diào)函數(shù)手動(dòng)應(yīng)答 on_message_callback=callback # 設(shè)置收到消息的回調(diào)函數(shù) ) # 應(yīng)答的本質(zhì)是告訴消息隊(duì)列可以將這條消息銷(xiāo)毀了 print('Waiting for messages. To exit press CTRL+C') # 一直處于等待接收消息的狀態(tài),如果沒(méi)收到消息就一直處于阻塞狀態(tài),收到消息就調(diào)用上面的回調(diào)函數(shù) channel.start_consuming()
這里只需要配置消費(fèi)者,生產(chǎn)者并不要修改
還有就是在上的使用方式在,都是一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者,還有一種情況就是,一個(gè)生產(chǎn)者和多個(gè)消費(fèi)者,即多個(gè)消費(fèi)者同時(shí)監(jiān)聽(tīng)一個(gè)消息隊(duì)列,這時(shí)候隊(duì)列里的消息就是輪詢(xún)分發(fā)(即如果消息隊(duì)列里有100條信息,如果有2個(gè)消費(fèi)者,那么每個(gè)就會(huì)收到50條信息),但是在某些情況下,不同的消費(fèi)者處理任務(wù)的能力是不同的,這時(shí)還按照輪詢(xún)的方式分發(fā)消息并不是很合理,那么只需要再配合手動(dòng)應(yīng)答的方式,設(shè)置消費(fèi)者接收的消息沒(méi)有處理完,隊(duì)列就不要給我放送新的消息即可,具體配置方式如下:
# coding=utf-8 ### 消費(fèi)者 import pika import time user_info = pika.PlainCredentials('root', 'root') connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) channel = connection.channel() # 如果指定的queue不存在,則會(huì)創(chuàng)建一個(gè)queue,如果已經(jīng)存在 則不會(huì)做其他動(dòng)作,生產(chǎn)者和消費(fèi)者都做這一步的好處是 # 這樣生產(chǎn)者和消費(fèi)者就沒(méi)有必要的先后啟動(dòng)順序了 channel.queue_declare(queue='queue') # 回調(diào)函數(shù) def callback(ch, method, properties, body): time.sleep(0)#通過(guò)設(shè)置休眠時(shí)間來(lái)模擬不同消費(fèi)者的處理時(shí)間 ch.basic_ack(delivery_tag=method.delivery_tag) print('消費(fèi)者收到:{}'.format(body.decode('utf-8'))) # prefetch_count表示接收的消息數(shù)量,當(dāng)我接收的消息沒(méi)有處理完(用basic_ack標(biāo)記消息已處理完畢)之前不會(huì)再接收新的消息了 channel.basic_qos(prefetch_count=1) # 還有就是這個(gè)設(shè)置必須在basic_consume之上,否則不生效 channel.basic_consume(queue='queue', # 接收指定queue的消息 auto_ack=False, # 指定為False,表示取消自動(dòng)應(yīng)答,交由回調(diào)函數(shù)手動(dòng)應(yīng)答 on_message_callback=callback # 設(shè)置收到消息的回調(diào)函數(shù) ) # 應(yīng)答的本質(zhì)是告訴消息隊(duì)列可以將這條消息銷(xiāo)毀了 print('Waiting for messages. To exit press CTRL+C') # 一直處于等待接收消息的狀態(tài),如果沒(méi)收到消息就一直處于阻塞狀態(tài),收到消息就調(diào)用上面的回調(diào)函數(shù) channel.start_consuming()
PS:這種情況必須關(guān)閉自動(dòng)應(yīng)答ack,改成手動(dòng)應(yīng)答。使用basicQos(perfetch=1)限制每次只發(fā)送不超過(guò)1條消息到同一個(gè)消費(fèi)者,消費(fèi)者必須手動(dòng)反饋告知隊(duì)列,才會(huì)發(fā)送下一個(gè)
(五)RabbitMQ發(fā)布訂閱模式
發(fā)布訂閱會(huì)將消息發(fā)送給所有的訂閱者,而消息隊(duì)列中的數(shù)據(jù)被消費(fèi)一次便消失。所以,RabbitMQ實(shí)現(xiàn)發(fā)布和訂閱時(shí),會(huì)為每一個(gè)訂閱者創(chuàng)建一個(gè)隊(duì)列,而發(fā)布者發(fā)布消息時(shí),會(huì)將消息放置在所有相關(guān)隊(duì)列中
這個(gè)模式中會(huì)引入交換機(jī)的概念,其實(shí)在RabbitMQ中,所有的生產(chǎn)者都不會(huì)直接把消息發(fā)送到隊(duì)列中,甚至生產(chǎn)者都不知道消息在發(fā)出后有沒(méi)有發(fā)送到queue中,事實(shí)上,生產(chǎn)者只能將消息發(fā)送給交換機(jī),由交換機(jī)來(lái)決定發(fā)送到哪個(gè)隊(duì)列中。
交換機(jī)的一端用來(lái)從生產(chǎn)者中接收消息,另一端用來(lái)發(fā)送消息到隊(duì)列,交換機(jī)的類(lèi)型規(guī)定了怎么處理接收到的消息,發(fā)布訂閱模式使用到的交換機(jī)類(lèi)型為 fanout ,這種交換機(jī)類(lèi)型非常簡(jiǎn)單,就是將接收到的消息廣播給已知的(即綁定到此交換機(jī)的)所有消費(fèi)者。
當(dāng)然,如果不想使用特定的交換機(jī),可以使用 exchange=’’ 表示使用默認(rèn)的交換機(jī),默認(rèn)的交換機(jī)會(huì)將消息發(fā)送到 routing_key 指定的queue,可以參考簡(jiǎn)單模式。
上代碼:
#生產(chǎn)者 import pika user_info = pika.PlainCredentials('root', 'root') connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) channel = connection.channel() # 創(chuàng)建一個(gè)指定名稱(chēng)的交換機(jī),并指定類(lèi)型為fanout,用于將接收到的消息廣播到所有queue中 channel.exchange_declare(exchange='交換機(jī)', exchange_type='fanout') # 將消息發(fā)送給指定的交換機(jī),在fanout類(lèi)型中,routing_key=''表示不用發(fā)送到指定queue中, # 而是將發(fā)送到綁定到此交換機(jī)的所有queue channel.basic_publish(exchange='交換機(jī)', routing_key='', body='這是一條測(cè)試消息')
#消費(fèi)者 import pika user_info = pika.PlainCredentials('root', 'root') connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) channel = connection.channel() channel.exchange_declare(exchange='交換機(jī)', exchange_type='fanout') # 使用RabbitMQ給自己生成一個(gè)專(zhuān)有的queue result = channel.queue_declare(queue='333') # result = channel.queue_declare(queue='', exclusive=True) queue_name = result.method.queue # 這里如果設(shè)置exclusive=True參數(shù),那么該隊(duì)列就是一個(gè)只有隊(duì)列,在消費(fèi)者結(jié)束后,該專(zhuān)有隊(duì)列也會(huì)自動(dòng)清除,如果queue=''沒(méi)有設(shè)置名字的話(huà),那么就會(huì)自動(dòng)生成一個(gè) # 不會(huì)重復(fù)的隊(duì)列名 # 將queue綁定到指定交換機(jī) channel.queue_bind(exchange='交換機(jī)', queue=queue_name) print(' [*] Waiting for message.') def callback(ch, method, properties, body): print("消費(fèi)者收到:{}".format(body.decode('utf-8'))) channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) channel.start_consuming()
該模式與簡(jiǎn)單模式的還有一個(gè)區(qū)別就是,這里的消息隊(duì)列都是由消費(fèi)者聲明的,所以如果是生產(chǎn)者先啟動(dòng),并將消息發(fā)給交換機(jī)的畫(huà),這里的消息就會(huì)丟失,所以我們也可以在消費(fèi)者端聲明隊(duì)列并綁定交換機(jī)(不能是專(zhuān)有隊(duì)列),所以仔細(xì)想想,其實(shí)這所謂的發(fā)布訂閱模式并沒(méi)有說(shuō)什么了不起,它不過(guò)是讓交換機(jī)同時(shí)推送多條消息給綁定的隊(duì)列,我們當(dāng)然也可以在簡(jiǎn)單模式的基礎(chǔ)上多進(jìn)行幾次basic_publish發(fā)送消息到指定的隊(duì)列。當(dāng)然我們這樣做的話(huà),可能就沒(méi)辦法做到由交換機(jī)的同時(shí)發(fā)送了,效率可能也沒(méi)有一次basic_publish的高
(六)RabbitMQ RPC模式
下面實(shí)現(xiàn)由rpc遠(yuǎn)程調(diào)用加減運(yùn)算
客戶(hù)端
import pika import uuid import json class RPC(object): def __init__(self): self.call_id = None self.response = None user_info = pika.PlainCredentials('root', 'root') self.connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) self.channel = self.connection.channel() # 創(chuàng)建一個(gè)此客戶(hù)端專(zhuān)用的queue,用于接收服務(wù)端發(fā)過(guò)來(lái)的消息 result = self.channel.queue_declare(queue='', exclusive=True) self.callback_queue = result.method.queue self.channel.basic_consume( queue=self.callback_queue, on_message_callback=self.on_response, auto_ack=True) def on_response(self, ch, method, props, body): # 判斷接收到的response是否屬于對(duì)應(yīng)request if self.call_id == props.correlation_id: self.response = json.loads(body.decode('utf-8')).get('result') def call(self, func, param): self.response = None self.call_id = str(uuid.uuid4()) # 為該消息指定uuid,類(lèi)似于請(qǐng)求id self.channel.queue_declare(queue='rpc_queue') self.channel.basic_publish( exchange='', routing_key='rpc_queue', # 將消息發(fā)送到該queue properties=pika.BasicProperties( reply_to=self.callback_queue, # 從該queue中取消息 correlation_id=self.call_id, # 為此次消息指定uuid ), body=json.dumps( { 'func': func, 'param': {'a': param[0], 'b': param[1]} } ) ) self.connection.process_data_events(time_limit=3)# 與start_consuming()相似,可以設(shè)置超時(shí)參數(shù) return self.response rpc = RPC() print("發(fā)送消息到消費(fèi)者,等待返回結(jié)果") response = rpc.call(func='del', param=(1, 2)) print("收到來(lái)自消費(fèi)者返回的結(jié)果:{}".format(response))
服務(wù)端
import pika import json user_info = pika.PlainCredentials('root', 'root') connection = pika.BlockingConnection(pika.ConnectionParameters('ip', 5672, '/', user_info)) channel = connection.channel() # 指定接收消息的queue channel.queue_declare(queue='rpc_queue') def add_number(a, b): return a + b def del_num(a, b): return a - b execute_map = { 'add': add_number, 'del': del_num } def on_request(ch, method, props, body): body = json.loads(body.decode('utf-8')) func = body.get('func') param = body.get('param') result = execute_map.get(func)(param.get('a'), param.get('b')) print('進(jìn)行{}運(yùn)算,并將結(jié)果返回個(gè)消費(fèi)者'.format(func)) ch.basic_publish(exchange='', # 使用默認(rèn)交換機(jī) routing_key=props.reply_to, # response發(fā)送到該queue properties=pika.BasicProperties( correlation_id=props.correlation_id), # 使用correlation_id讓此response與請(qǐng)求消息對(duì)應(yīng)起來(lái) body=json.dumps({'result': result})) ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_qos(prefetch_count=1) # 從rpc_queue中取消息,然后使用on_request進(jìn)行處理 channel.basic_consume(queue='rpc_queue', on_message_callback=on_request) print(" [x] Awaiting RPC requests") channel.start_consuming()
(七)說(shuō)點(diǎn)啥
對(duì)于rabbitmq的模式還有Routing模式和Topics模式等,這里就不復(fù)述了,其實(shí)pika對(duì)于RabbitMQ的使用還有很多細(xì)節(jié)和參數(shù)值得深究。這篇博客也就是簡(jiǎn)單的記錄下我對(duì)pika操作raabbitmq過(guò)程和簡(jiǎn)單的理解
參考鏈接:
https://www.cnblogs.com/guyuyun/p/14970592.html
https://blog.csdn.net/wohu1104/category_9023593.html
(八)結(jié)語(yǔ)
到此這篇關(guān)于python對(duì)RabbitMQ的簡(jiǎn)單入門(mén)使用的文章就介紹到這了,更多相關(guān)python RabbitMQ使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用sqlalchemy構(gòu)建Django連接池的實(shí)例
今天小編就為大家分享一篇用sqlalchemy構(gòu)建Django連接池的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-08-08python rolling regression. 使用 Python 實(shí)現(xiàn)滾動(dòng)回歸操作
這篇文章主要介紹了python rolling regression. 使用 Python 實(shí)現(xiàn)滾動(dòng)回歸操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06Python Django 命名空間模式的實(shí)現(xiàn)
這篇文章主要介紹了Python Django 命名空間模式的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08Effective Python bytes 與 str 的區(qū)別
這篇文章主要介紹了Effective Python bytes 與 str 的區(qū)別,Python 有兩種類(lèi)型可以表示字符序列,下面圍繞Python bytes 與 str 的相關(guān)資料展開(kāi)內(nèi)容,需要的朋友可以參考一下2021-11-11詳解Python數(shù)據(jù)可視化編程 - 詞云生成并保存(jieba+WordCloud)
這篇文章主要介紹了Python數(shù)據(jù)可視化編程 - 詞云生成并保存(jieba+WordCloud),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03關(guān)于微信小程序爬蟲(chóng)token自動(dòng)更新問(wèn)題
本文主要介紹了關(guān)于微信小程序爬蟲(chóng)關(guān)于token自動(dòng)更新問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Python-apply(lambda x: )的使用及說(shuō)明
這篇文章主要介紹了Python-apply(lambda x: )的使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02簡(jiǎn)要講解Python編程中線(xiàn)程的創(chuàng)建與鎖的使用
這篇文章主要介紹了簡(jiǎn)要講解Python編程中線(xiàn)程的創(chuàng)建與鎖的使用,Python中雖然有GIL的存在,但依然是能夠創(chuàng)建多個(gè)線(xiàn)程來(lái)交替使用的,需要的朋友可以參考下2016-02-02Pycharm及python安裝詳細(xì)步驟及PyCharm配置整理(推薦)
這篇文章主要介紹了Pycharm及python安裝詳細(xì)步驟以及PyCharm配置整理,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04