app自动化11 线程实现多个脚本在多个手机运行
线程
多任务简单介绍
- 有很多事情在现实生活的场景中是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的。
- 多任务,就是能够在同一时间同时进行多个任务。
这样同时进行多个任务,有一个极大的好处,那就是节省时间
代码举例
import time
import threading
def sing():
for i in range(5):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
import time
import threading
def sing():
for i in range(5):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
sing()
dance()
第一段代码开启3个线程,分别是主线程,子线程t1,子线程t2,耗时一共是5秒
第二段代码开启1个线程,那就是主线程,耗时一共是10秒
为什么第一段代码耗时只要5秒,而第二段代码耗时要10秒呢?
下面就由sunt来为大家说下原因吧,先分析第一段代码:
主线程先开始运行,然后让两个小弟,也就是子线程t1,t2。分别去执行sing()和dance()代码,这两个小弟是并行执行的,并不是说小弟t1先执行完,
小弟t2才去执行,而是两个小弟同时执行,故耗时为5秒,图解如下:
打印出来结果:
唱歌
跳舞
跳舞
唱歌
跳舞
唱歌
跳舞
唱歌
跳舞
唱歌
这是因为当他们从休眠到唤醒是同时的,故资源掠夺的不确定性,有可能跳舞先执行,也有可能唱歌先执行,不过一定是成对出现的。
并行执行耗时总时间为5秒。
接下来分析第二段代码:
主线程先开始执行,然后主线程执行sing()代码块,等待sing()代码块执行完之后,才开始执行dance()代码块。故耗时为sing()代码块
的时间加dance()代码块的时间,一共为10秒。图解如下:
多任务的原理
什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。
单核cpu工作原理
- 现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?
- 答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。实际上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
- 真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。
多核cpu工作原理
和单核类似,相当于多了一个干活的人。
并发:指的是任务数多于cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行
(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的
- 并行和并发都算是多任务,但并行实际上才是真正的多任务,并发是假的。
线程的两张创建方式
- 直接使用threading模块的Thread类,指定要执行的方法,再调用start
- 使用继承的方式,继承Thread类,重新run方法,创建这个对象后,再调用start
查看当前程序线程数量
threading.enumerate()
- 获取所有线程,返回的是一个列表。
- 如果需要个数,使用len(threading.enumerate())
为子线程传递参数
target方式
import time
import threading
def sing(nums):
for i in range(nums):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
t1 = threading.Thread(target=sing, args=(3,))
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
类继承方式
import threading
class Work1(threading.Thread):
def __init__(self, nums):
super().__init__()
self.nums = nums
def run(self):
for i in range(self.nums):
print("haha")
def main():
w = Work1(2)
w.start()
if __name__ == "__main__":
main()
Appium多端口
目标,让一个脚本去跑到多台手机。
注意点: appium sever端口要不同,开启多个。bootstrap端口要不同,开启多个。udid需要指定,udid表示设备的唯一表示符号,通过 adb devices 查看。 前半部分都是,比如模拟器的(192.168.57.101:5555)。
appium server 和 bootstrap 和 udid 应该是成对出现的。
命令:
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
-p 表示 appium的端口
-bp 表示 bootstrap的端口
-U 表示设备的标识符
修改init_driver让,init_driver接受port的参数。并且进行对应的连接。
记得,创建的是不同的driver对象。
因为如果使用threading.Thread的这种形式,需要指定执行的函数,所以,把需要执行的代码,封装成一个函数。然后使用
ports = ["4723", "4725"]
for i in ports:
threading.Thread(target=do, args=(i,)).start()
来去执行创建多个driver并且进行脚本的操作。
下面看图解就知道appium多端口的工作原理了。
依照上图可以知道,如果要想让一段脚本操作两个手机,那么我要做的就是,开启两个appium服务和两个bootstrap服务,并且端口号不能相同,
appium和bootstrap是一对,并且有两个手机,还要指定手机设备号,故命令如下
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
appium -p 4725 -bp 4726 -U 192.168.57.102:5555
代码实现
命令行先启动appium并指定端口,并指定bootstrap端口和手机设备号
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
appium -p 4725 -bp 4726 -U 192.168.57.102:5555
base_driver.py
from appium import webdriver
def init_driver(port="4723"):
# server 启动参数
desired_caps = dict()
# 设备信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.164.101:5555'
# app信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 中文
desired_caps['unicodeKeyboard'] = True
desired_caps['resetKeyboard'] = True
# 不重置应用
desired_caps['noReset'] = True
# toast
# desired_caps['automationName'] = 'Uiautomator2'
# 声明对象
driver = webdriver.Remote('http://localhost:' + port + '/wd/hub', desired_caps)
return driver
login_page.py
from base_action import BaseAction
class LoginPage(BaseAction):
pass
demo.py
import threading
from selenium.webdriver.common.by import By
from base_driver import init_driver
from base_action import BaseAction
from login_page import LoginPage
def do(port):
driver = init_driver(port)
login_page = LoginPage(driver)
if "4723" == port:
login_page.click((By.XPATH, "text,更多"))
else:
login_page.click((By.XPATH, "text,WLA"))
def main():
//根据ports不同,driver可以连接不同的手机
ports = ["4723", "4725"]
for i in ports:
threading.Thread(target=do, args=(i,)).start()
if __name__ == '__main__':
main()