本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。
线程的概念,不管在哪种语言中,大家都应该接触了不少,我这里就不再说明,这一节就用几个小例子说明一下,线程和锁在Python中的使用。
一、直接使用Thread构造方法
开辟四个线程异步执行任务,其中前三个线程执行的都是单独的一个网络请求,而最后一个线程执行了两个网络请求。
import threading
import requests
def display_info(code):
url = 'http://hq.sinajs.cn/list=' + code
response = requests.get(url).text
print(response)
def single_task(codes):
for code in codes:
code = code.strip()
display_info(code)
def exec_task(tasks):
threads = []
for t in tasks:
threads.append(threading.Thread(target = single_task, args=(t, )))
for t in threads:
t.start()
for t in threads:
t.join()
def main():
stocks = ['sh600001', 'sh600002', 'sh600003', 'sh600004', 'sh600005']
step = int(len(stocks) / 4)
t1 = stocks[0: step]
t2 = stocks[step: step * 2]
t3 = stocks[step * 2: step * 3]
t4 = stocks[step * 3:]
exec_task([t1, t2, t3, t4])
if __name__ == '__main__':
main()
代码中,需要说明的是下面这句代码:
threads.append(threading.Thread(target = single_task, args=(t, )))
1. 调用线程的构造方法,需要传入两个参数。第一个是执行线程的方法,本例中是single_task, 另一个就是线程调用方法传入的参数args
2. 注意args传入参数的格式是一个元祖,并且第二个参数是空。这是由于语法格式决定的,这个只能传入元祖,如果我们将args传入的值直接写成args=t, 则会报下面的错误。
TypeError: single_task() takes 1 positional argument but 2 were given
二、自定义Thread类
开辟三个线程,每个线程打印五次。
import time
import threading
class MyThread(threading.Thread):
def run(self):
name = threading.current_thread().name
for i in range(5):
print('sub thread_{}, @number:{}'.format(name, i))
time.sleep(1)
def main():
name = threading.current_thread().name
print('Start main threading %s' % name)
threads = [MyThread() for i in range(3)]
for t in threads:
t.start()
# join (上述的例子中,主线程结束了,子线程还在运行。如果需要主线程等待子线程执行完毕再退出,可是使用线程的join方法)
for t in threads:
t.join()
print('End main threading')
if __name__ == '__main__':
main()
代码中有两点需要说明:
1. 主线程中的线程名称是0,其他的线程名称不是0.
2. 创建三个线程使用了快速创建数组的方式 threads = [MyThread() for i in range(3)]
三、锁的使用说明
使用多线程,大家都会遇到线程资源竞争的问题,解决方案就是对公用资源加锁。当有一个线程在访问共有资源的时候,其他线程排队等待。Python加锁的大致代码如下:
import time
import threading
lock = threading.Lock()
balance = 0
def change_it(n):
global balance
balance = balance + n
balance = balance - n
def run_thread(num):
for i in range(1000):
lock.acquire()
try:
change_it(num)
finally:
lock.release()
thread1 = threading.Thread(target = run_thread, args=(5, ))
thread2 = threading.Thread(target = run_thread, args=(8, ))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print('balance value is %d' % balance)
代码中有两点需要说明:
1. 加锁使用的是lock.acquire(), 解锁使用的是lock.release()
2. 代码使用了try finally语法,原因是因为如果change_it(num)这个方法执行出现了异常,那么锁就解不掉了。