python多线程
python中有两种方式实现线程
1.实例化一个threading.Thread的对象,并传入一个初始化函数对象(initial function )作为线程执行的入口;
2.继承threading.Thread,并重写run函数
- 方式1:创建threading.Thread对象
from threading import Thread
import time
def tstart(arg):
time.sleep(0.5)
print("%s running...." % arg)
if __name__ == '__main__':
# 创建线程对象,(参数1:target 固定格式跟函数名称,不加括号 参数2:args是一个元组,)
t1 = Thread(target=tstart, args=('This is thread 1',))
t2 = Thread(target=tstart, args=('This is thread 2',))
t1.start()
t2.start()
print("This is main function")
结果:
This is main function
This is thread 2 running....
This is thread 1 running....
- 方式2:继承threading.Thread,并重写run
import threading
import time
class CustomThread(threading.Thread):
def __init__(self, thread_name):
# step 1: call base __init__ function
super(CustomThread, self).__init__(name=thread_name)
self._tname = thread_name
def run(self):
# step 2: overide run function
time.sleep(0.5)
print("This is %s running...." % self._tname)
if __name__ == "__main__":
t1 = CustomThread("thread 1")
t2 = CustomThread("thread 2")
t1.start()
t2.start()
print("This is main function")
执行结果同方式1.
上面两种方法本质上都是直接或者间接使用Thread类,导入Thread类的方式不同,有的直接导入,有的间接导入
关联上面两种创建线程的方式:
import threading
import time
class CustomThread(threading.Thread):
def __init__(self, thread_name, target = None):
# step 1: call base __init__ function
super(CustomThread, self).__init__(name=thread_name, target=target, args = (thread_name,))
self._tname = thread_name
def run(self):
# step 2: overide run function
# time.sleep(0.5)
# print("This is %s running....@run" % self._tname)
super(CustomThread, self).run()
def target(arg):
time.sleep(0.5)
print("This is %s running....@target" % arg)
if __name__ == "__main__":
t1 = CustomThread("thread 1", target)
t2 = CustomThread("thread 2", target)
t1.start()
t2.start()
print("This is main function")
结果:
This is main function
This is thread 1 running....@target
This is thread 2 running....@target
上面这段代码说明:
两种方式创建线程,指定的参数最终都会传给threading.Thread类;
传给线程的目标函数是在基类Thread的run函数体中被调用的,如果run没有被重写的话。
threading模块的一些属性和方法可以参照官网,这里重点介绍一下threading.Thread对象的方法
下面是threading.Thread提供的线程对象方法和属性
- start():创建线程后通过start启动线程,等待CPU调度,为run函数执行做准备;
- run():线程开始执行的入口函数,函数体中会调用用户编写的target函数,或者执行被重载的run函数;
- join([timeout]):阻塞挂起调用该函数的线程,直到被调用线程执行完成或超时。通常会在主线程中调用该方法,等待其他线程执行完成。
- name、getName()&setName():线程名称相关的操作;
- ident:整数类型的线程标识符,线程开始执行前(调用start之前)为None;
- isAlive()、is_alive():start函数执行之后到run函数执行完之前都为True;
- daemon、isDaemon()&setDaemon():守护线程相关;>
多线程执行
在主线程中创建若线程之后,他们之间没有任何协作和同步,除主线程之外每个线程都是从run开始被执行,直到执行完毕。
join
我们可以通过join方法让主线程阻塞,等待其创建的线程执行完成。
import threading
import time
def tstart(arg):
print("%s running....at: %s" % (arg,time.time()))
time.sleep(1)
print("%s is finished! at: %s" % (arg,time.time()))
if __name__ == '__main__':
t1 = threading.Thread(target=tstart, args=('This is thread 1',))
t1.start()
t1.join() # 当前线程阻塞,等待t1线程执行完成
print("This is main function at:%s" % time.time())
结果:
This is thread 1 running....at: 1564906617.43
This is thread 1 is finished! at: 1564906618.43
This is main function at:1564906618.43
deamon守护线程
可以通过将创建的线程指定为守护线程(daemon),这样主线程执行完毕之后会立即结束未执行完的线程,然后结束程序。
import threading
import time
def tstart(arg):
print("%s running....at: %s" % (arg,time.time()))
time.sleep(1)
print("%s is finished! at: %s" % (arg,time.time()))
if __name__ == '__main__':
t1 = threading.Thread(target=tstart, args=('This is thread 1',))
t1.setDaemon(True)
t1.start()
# t1.join() # 当前线程阻塞,等待t1线程执行完成
print("This is main function at:%s" % time.time())
结果:
This is thread 1 running....at: 1564906847.85
This is main function at:1564906847.85
python多进程
python提供multiprocessing用于创建多进程
创建进程
创建进程的方式和创建线程的方式类似:
- 实例化一个multiprocessing.Process的对象,并传入一个初始化函数对象(initial function )作为新建进程执行入口;
from multiprocessing import Process
import os, time
def pstart(name):
# time.sleep(0.1)
print("Process name: %s, pid: %s "%(name, os.getpid()))
if __name__ == "__main__":
subproc = Process(target=pstart, args=('subprocess',))
subproc.start()
subproc.join()
print("subprocess pid: %s"%subproc.pid)
print("current process pid: %s" % os.getpid())
结果:
Process name: subprocess, pid: 4888
subprocess pid: 4888
current process pid: 9912
- 继承multiprocessing.Process,并重写run函数;
from multiprocessing import Process
import os, time
class CustomProcess(Process):
def __init__(self, p_name, target=None):
# step 1: call base __init__ function()
super(CustomProcess, self).__init__(name=p_name, target=target, args=(p_name,))
def run(self):
# step 2:
# time.sleep(0.1)
print("Custom Process name: %s, pid: %s "%(self.name, os.getpid()))
if __name__ == '__main__':
p1 = CustomProcess("process_1")
p1.start()
p1.join()
print("subprocess pid: %s"%p1.pid)
print("current process pid: %s" % os.getpid())
注意 由于每一个进程拥有独立的内存地址空间且互相隔离,因此不同进程看到的share_data是不同的、分别位于不同的地址空间,同时访问不会有问题。
如何共享进程中的数据呢?
两个进程必须使用同一个队列. 否则数据传输不了
from multiprocessing import Process,Queue #注意:这里导入的队列是进程模块下的
# 创建队列对象
q = Queue()
p1 = Process(target=get_img_src, args=(q,))
p2 = Process(target=download_img, args=(q,))
p1.start()
p2.start()
# 比如第一个进程是获取url 路径,那么在get_img_src()函数中我们就可以把获取到的url的值存入队列中 q.put(xxxx) ,那么取值为q.get(),这样我们就可以实现进程中数据的共享了
线程池
from concurrent.futures import ThreadPoolExecutor
def fn(name):
for i in range(1000):
print(name, i)
if __name__ == '__main__':
with ThreadPoolExecutor(10) as t:
for i in range(100):
t.submit(fn, name=f"线程{i}")
如果任务有返回值怎么办?
def func(name):
time.sleep(2)
return name
def do_callback(res):
print(res.result())
if __name__ == '__main__':
with ThreadPoolExecutor(10) as t:
names = ["线程1", "线程2", "线程3"]
for name in names:
# 方案一, 添加回调
t.submit(func, name).add_done_callback(do_callback)
if __name__ == '__main__':
start = time.time()
with ThreadPoolExecutor(10) as t:
names = [5, 2, 3]
# 方案二, 直接用map进行任务分发. 最后统一返回结果
results = t.map(func, names) # 结果是按照你传递的顺序来执行的, 代价就是如果第一个没结束. 后面就都没结果
for r in results:
print("result", r)
print(time.time() - start)
原创文章,作者:wure,如若转载,请注明出处:https://blog.ytso.com/tech/java/272017.html