Python多线程

瘦欲@ 提交于 2020-01-29 04:03:12

threading 模块

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

Thread类提供了以下方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

Thread构造器

在线程里,传递参数有三种方法:

  • 使用元组传递threading.Thread(target=方法名,args=(参数1,参数2, ...))
  • 使用字典传递 threading.Thread(target=方法名, kwargs={"参数名": 参数1, "参数名": 参数2, ...})
  • 混合使用元组和字典 threading.Thread(target=方法名,args=(参数1, 参数2, ...), kwargs={"参数名": 参数1,"参数名": 参数2, ...})
import threading
import time

def run(a, b, c):
    print(a, b, c)
    for i in range(3):
        print("%s %s %d" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), threading.currentThread().name, i))
        time.sleep(1)


threading.Thread(name="Thread-1", target=run, args=(1, 2, 3)).start()
threading.Thread(name="Thread-2", target=run, kwargs={"b": 2, "a": 1, "c": 3}).start()
threading.Thread(name="Thread-3", target=run, args=(1,), kwargs={"c": 3, "b": 2}).start()

继承线程类Thread

import threading
import time


class MyThread(threading.Thread):

    def run(self) -> None:
        print("%s running " % threading.currentThread().name)
        for i in range(3):
            print(
                "%s %s %d" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), threading.currentThread().name, i))
            time.sleep(1)


thread1 = MyThread()
thread1.start()

thread2 = MyThread()
thread2.start()

thread1.join()
thread2.join()
print("%s the end..." % threading.currentThread().name)

线程同步锁

对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。

线程不安全示例:启动5个线程,每个线程循环1000000次,正常结果为1000000 * 5 = 5000000, 实际结果一般不是这个值。

import threading
import time


count = 0


class MyThread(threading.Thread):
    def run(self) -> None:
        global count
        for i in range(1000000):
            count += 1
        print("%s end %s" % (threading.currentThread().name, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))

for _ in range(5):
    thread = MyThread()
    thread.start()

time.sleep(5)
print("%s the end... count=%d" % (threading.currentThread().name, count))


# Thread-1 end 2019-12-06 18:05:31
# Thread-2 end 2019-12-06 18:05:31
# Thread-3 end 2019-12-06 18:05:31
# Thread-4 end 2019-12-06 18:05:31
# Thread-5 end 2019-12-06 18:05:31
# MainThread the end... count=2203600

线程安全示例

Python通过锁机制来实现线程安全。通过threading.Lock()来获取锁,通过acquire()方法获取锁,通过release()释放锁。

import threading
import time

count = 0
threadLock = threading.Lock()


class MyThread(threading.Thread):
    def run(self) -> None:
        # 获取锁
        threadLock.acquire()
        global count
        for i in range(1000000):
            count += 1
        print("%s end %s" % (threading.currentThread().name, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
        # 释放锁
        threadLock.release()


for _ in range(5):
    thread = MyThread()
    thread.start()

time.sleep(5)
print("%s the end... count=%d" % (threading.currentThread().name, count))


# Thread-1 end 2019-12-06 18:10:20
# Thread-2 end 2019-12-06 18:10:20
# Thread-3 end 2019-12-06 18:10:20
# Thread-4 end 2019-12-06 18:10:20
# Thread-5 end 2019-12-06 18:10:20
# MainThread the end... count=5000000

上述示例acquire()和release()必须成对调用,开发中有可能写了acquire()而漏掉release(),Python提供了一个比较好用的语法with语法,可自动获取锁和自动释放锁。

import threading
import time

count = 0
threadLock = threading.Lock()


class MyThread(threading.Thread):
    def run(self) -> None:
        global count
        with threadLock:
            for i in range(1000000):
                count += 1
            print("%s end %s" % (threading.currentThread().name, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))


for _ in range(5):
    thread = MyThread().start()

time.sleep(5)
print("%s the end... count=%d" % (threading.currentThread().name, count))

队列

  • Queue(length): 指定队列的长度
  • qsize() 返回队列的大小
  • empty() 如果队列为空,返回True,反之False
  • full() 如果队列满了,返回True,反之False
  • get([block[, timeout]])获取队列,timeout等待时间
  • put(item) 写入队列
  • join() 实际上意味着等到队列为空,再执行别的操作
import queue
import threading
import time

exit_flag = 1
workQueue = queue.Queue(10)


class MyThread(threading.Thread):
    def run(self) -> None:
        print("%s end %s" % (threading.currentThread().name, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
        while exit_flag:
            if not workQueue.empty():
                data = workQueue.get()
                print("%s  %s  %s" % (threading.currentThread().name, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), data))
            else:
                break
            time.sleep(1)


# 往队列中放内容
for item in range(10):
    workQueue.put(item)

# 三个线程同时从队列中消费
threads = []
for i in range(3):
    thread = MyThread()
    thread.name = "Thread-" + str(i)
    thread.start()
    threads.append(thread)

# 等待队列清空
while not workQueue.empty():
    pass
else:
    exit_flag = 0

# 等待所有线程完成
for t in threads:
    t.join()

print("主线程退出")
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!