Python多线程

首先我们区分一下线程和进程:

进程和线程的关系:

(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。

(3)处理机分给线程,即真正在处理机上运行的是线程

(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体.

进程与线程的区别:

(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行

(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.

(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
多线程类似于同时执行多个不同程序,多线程运行有如下优点:
使用线程可以把占据长时间的程序中的任务放到后台去处理。

用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。

程序的运行速度可能加快。

在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
这里说明一下thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 “_thread”。
Python创建Thread对象语法如下:
    import threading
    threading.Thread(target=None, name=None,  args=())
主要参数说明:
target 是函数名字,需要调用的函数。
name 设置线程名字。
args 函数需要的参数,以元祖( tuple)的形式传入
Thread 对象主要方法说明:
run(): 用以表示线程活动的方法。
start():启动线程活动。
join(): 等待至线程中止。
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。
Python中实现多线程有两种方式:函数创建线程和创建线程类
函数创建线程:
import threading
import time, random, math


# idx 循环次数
def printNum(idx):
    for num in range(idx):
        # 打印当前运行的线程名字
        print("{0}\tnum={1}".format(threading.current_thread().getName(), num))
        # 随机生成一个数*2,向上取整使线程休眠,这里*2是为了时间间隔大一些
        delay = math.ceil(random.random() * 2)
        #进行休眠
        time.sleep(delay)


if __name__ == '__main__':
    #这里args()的值就是printNum函数的参数
    th1 = threading.Thread(target=printNum, args=(2,), name="thread1")
    th2 = threading.Thread(target=printNum, args=(3,), name="thread2")

    # 启动2个线程
    th1.start()
    th2.start()

    # 等待至线程中止
    th1.join()
    th2.join()
    print("{0} 线程结束".format(threading.current_thread().getName()))
创建线程的时候,只需要传入一个执行函数和函数的参数即可完成threading.Thread实例的创建。
运行结果:
thread1 num=0
thread2 num=0
thread1 num=1
thread2 num=1
thread2 num=2
MainThread 线程结束
创建线程类:
import threading
import time, random, math

#继承Thread类
class MutliThread(threading.Thread):
    def __init__(self, threadName, num):
        threading.Thread.__init__(self)
        self.name = threadName
        self.num = num
    #重写run方法
    def run(self):
        for i in range(self.num):
            print("{0} i={1}".format(threading.current_thread().getName(), i))
            delay = math.ceil(random.random() * 2)
            time.sleep(delay)


if __name__ == '__main__':
    thr1 = MutliThread("thread1", 3)
    thr2 = MutliThread("thread2", 2)

    # 启动线程
    thr1.start()
    thr2.start()

    # 等待至线程中止
    thr1.join()
    thr2.join()
    print("{0} 线程结束".format(threading.current_thread().getName()))
直接创建threading.Thread的子类来创建一个线程对象,实现多线程。通过继承Thread类,并重写Thread类的run()方法,在run()方法中定义具体要执行的任务。
运行结果:
thread1 i=0
thread2 i=0
thread1 i=1
thread2 i=1
thread1 i=2
MainThread 线程结束
守护线程:
上例中的join方法的作用是阻塞,等待子线程结束,join方法有一个参数是timeout,即如果主线程等待timeout,子线程还没有结束,则主线程强制结束子线程。简单来说就是使主线程等待子线程结束后再结束。如果子线程不使用join()函数,主线程和子线程是并行运行的,没有依赖关系,主线程执行了,子线程也在执行。
在多线程开发中,如果子线程设定为了守护线程,守护线程会等待主线程运行完毕后被销毁。一个主线程可以设置多个守护线程,守护线程运行的前提是,主线程必须存在,如果主线程不存在了,守护线程会被销毁。
import threading, time

def run(taskName):
    print("任务:", taskName)
    time.sleep(2)
    print("{0} 任务执行完毕".format(taskName))  # 查看每个子线程

if __name__ == '__main__':
    start_time = time.time()
    for i in range(3):
        thr = threading.Thread(target=run, args=("task-{0}".format(i),))
        thr.start()

    # 查看主线程和当前活动的所有线程数,active_count方法是查看当前线程数
    print("{0}线程结束,当线程数量={1}".format(threading.current_thread().getName(), threading.active_count()))
    print("消耗时间:", time.time() - start_time)
运行结果:
    任务: task-0
    任务: task-1
    任务: task-2
    MainThread线程结束,当线程数量=4
    消耗时间: 0.0009751319885253906
    task-2 任务执行完毕
    task-0 任务执行完毕
    task-1 任务执行完毕
从返回结果可以看出,当前的线程个数是4,线程个数=主线程数 + 子线程数,在本例中有1个主线程和3个子线程。主线程执行完毕后,等待子线程执行完毕,程序才会退出。
在这里我们把所有的子线程都设置为守护线程。子线程变成守护线程后,只要主线程执行完毕,程序不管子线程有没有执行完毕,程序都会退出。使用线程对象的setDaemon(True)函数来设置守护线程。
import threading, time

def run(taskName):
    print("任务:", taskName)
    time.sleep(2)
    print("{0} 任务执行完毕".format(taskName))

if __name__ == '__main__':
    start_time = time.time()
    for i in range(3):
        thr = threading.Thread(target=run, args=("task-{0}".format(i),))

        # 把子线程设置为守护线程,一定在启动线程前设置
        thr.setDaemon(True)
        thr.start()

    # 查看主线程和当前活动的所有线程数
    thrName = threading.current_thread().getName()
    thrCount = threading.active_count()
    print("{0}线程结束,当线程数量={1}".format(thrName, thrCount))
    print("消耗时间:", time.time() - start_time)
运行结果:
    任务: task-0
    任务: task-1
    任务: task-2
    MainThread线程结束,当线程数量=4
    消耗时间: 0.0010023117065429688
这里就可以看出,设置了守护线程以后当主线程结束了,子线程也随之销毁。
线程互斥锁同步线程
import threading

balance = 100

def change(num, counter):
    global balance
    for i in range(counter):
        balance += num
        balance -= num
        if balance != 100:
            # 如果输出这句话,说明线程不安全
            print("balance=%d" % balance)
            break

if __name__ == "__main__":
    thr1 = threading.Thread(target=change, args=(100, 500000), name='t1')
    thr2 = threading.Thread(target=change, args=(100, 500000), name='t2')
    thr1.start()
    thr2.start()
    thr1.join()
    thr2.join()
    print("{0} 线程结束".format(threading.current_thread().getName()))
运行结果:
    balance=200
    MainThread 线程结束
本例中在for循环的过程中,由于线程同时进行,我们定义的全局变量balance也同时被调用,只要循环次数足够,一定会有一次在t1执行balance += num后t2也执行balance += num,此时balance值为300,然后t1在进行balance -= num,此时balance值为200,进入if循环。
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。互斥锁为资源引入一个状态:锁定/非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
#创建锁
mutex = threading.Lock()
#锁定
mutex.acquire([timeout])
#释放
mutex.release()
import threading

balance = 100

lock = threading.Lock()

def change(num, counter):
    global balance
    for i in range(counter):
        # 先要获取锁
        lock.acquire()

        balance += num
        balance -= num

        # 释放锁
        lock.release()

        if balance != 100:
            # 如果输出这句话,说明线程不安全
            print("balance=%d" % balance)
            break

if __name__ == "__main__":
    thr1 = threading.Thread(target=change,args=(100,500000),name='t1')
    thr2 = threading.Thread(target=change,args=(100,500000),name='t2')
    thr1.start()
    thr2.start()
    thr1.join()
    thr2.join()
    print("{0} 线程结束".format(threading.current_thread().getName()))
运行结果:
MainThread 线程结束
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python多线程可以使用内置的`threading`模块来实现。这个模块提供了一些对象和方法,可以方便地创建和管理线程。 以下是一个简单的多线程示例,它创建了两个线程,每个线程都打印数字1到5: ```python import threading def print_numbers(): for i in range(1, 6): print(threading.current_thread().name, i) # 创建两个线程 t1 = threading.Thread(target=print_numbers) t2 = threading.Thread(target=print_numbers) # 启动线程 t1.start() t2.start() # 等待线程结束 t1.join() t2.join() print("All threads have finished.") ``` 在这个示例中,我们首先定义了一个`print_numbers()`函数,它用于打印数字1到5,并且在每个数字前面打印线程的名称。然后,我们创建了两个线程`t1`和`t2`,它们都指向`print_numbers()`函数。接下来,我们启动这两个线程,并等待它们完成,最后输出"All threads have finished."。 注意,`threading.current_thread().name`用于获取当前线程的名称。在这个示例中,我们没有指定线程的名称,因此它们将默认为"Thread-1"和"Thread-2"。 多线程可以提高程序的执行效率,但是也需要注意线程安全问题,比如并发访问共享变量可能会导致数据不一致的问题。因此,在编写多线程程序时,需要特别注意线程安全问题。 ### 回答2: Python多线程是指在一个程序中同时执行多个线程,每个线程都可以独立执行不同的任务。Python多线程是基于线程模块实现的,通过创建多个线程对象来实现多线程的功能。 Python多线程的使用需要导入threading模块,使用threading.Thread类来创建线程对象。通过调用线程对象的start()方法,线程就会开始执行。线程可以是执行同一个函数,也可以是执行不同的函数,甚至可以是执行不同的类的方法。 线程之间可以共享全局变量,但需要避免多个线程同时修改全局变量的情况,可以通过互斥锁机制来保证数据的一致性。 Python多线程的优点是能够提高程序的执行效率,特别是在IO操作较多的情况下,多线程可以充分利用CPU的空闲时间。另外,多线程还可以实现一些并发的功能,例如同时下载多个文件、同时处理多个网络请求等。 然而,Python多线程在处理CPU密集型任务上并不适用,因为在Python中,多线程并不能利用多核CPU的优势,由于Python的GIL(全局解释器锁)机制,多线程在CPU密集型任务上的效率并不比单线程高。 总结来说,Python多线程适用于IO密集型任务,能够提高程序的执行效率和实现并发的功能,但对于CPU密集型任务,单线程可能更适合。 ### 回答3: Python 多线程是指在一个程序中同时运行多个线程,每个线程独立执行其任务。Python 中的多线程可以通过使用 threading 模块来实现。 在 Python 中,多线程的主要优势是能够提升程序的执行效率。通过多线程,可以将耗时较长的任务分配给不同的线程来并行执行,从而缩短程序的总执行时间。这尤其适用于那些需要频繁进行网络请求、IO 操作或者计算密集型任务的程序。 使用 Pythonthreading 模块可以很方便地创建和管理线程。通过创建 Thread 对象并传入要执行的函数,就可以创建一个新的线程。可以使用 start() 方法来启动线程,并使用 join() 方法来等待线程执行完成。 需要注意的是,Python 中的多线程并不能真正实现并行执行,而是通过在不同任务之间快速切换来模拟并行。这是由于 Python 的全局解释器锁(GIL)的存在,它使得同一时间只有一个线程能够执行 Python 的字节码。因此,在计算密集型任务上,使用多线程并不能获得真正的并行加速。 另外,多线程在处理共享资源时需要注意线程安全问题。多个线程同时访问和修改共享数据可能会导致数据不一致或者竞争条件。在这种情况下,可以通过使用锁(Lock)等同步机制来确保数据的正确访问和更新。 总而言之,Python 多线程可以提升程序的执行效率,适用于需要进行网络请求、IO 操作或者并发处理的任务。然而,在计算密集型任务上,并不能实现真正的并行加速。同时,在处理共享资源时需要注意线程安全问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值