我正在寻找一种在 silverlight 中将大量工作放在单个后台线程上的方法
我在 Windows Phone 7 的应用程序中遇到了一个有趣的问题。 现在,我正在发送大约两打左右的小(几 KB)xml 文件请求,以保持快速变化的信息(准确地说是公交车位置)。我有一个计时器每 10 秒计时一次,以异步发送请求。
检索到的数据通过异步回调进行处理,以验证请求是否带文件返回,并将文件存储到isolatedStorage 中。当需要数据时(通过 UI 的视图模型),将从isolatedStorage 中读取文件,解析为内部对象(基本上是地理坐标和一些字符串)并使用。
1)我在这里遇到了手机CPU的限制,只是一点点。如果我解析所有总线数据以确定 UI 线程上哪些总线路线处于活动状态,则该线程的速度会明显减慢。我将工作转移到 bakground 工作程序中,如下所示:
public class RunningWorkerHelper
{
public BusRouteIdModel Route { get; set; }
public Visibility Visible { get; set; }
}
public class RunningWorker
{
BackgroundWorker bw;
Queue<BusRouteIdModel> workQueue;
public RunningWorker()
{
bw = new BackgroundWorker();
workQueue = new Queue<BusRouteIdModel>();
bw.DoWork += CheckIfRunning;
bw.RunWorkerCompleted += CheckRunningCompleted;
}
public void QueueWorkItem(BusRouteIdModel route)
{
workQueue.Enqueue(route);
StartWorkItem();
}
void StartWorkItem()
{
if (!bw.IsBusy && workQueue.Count > 0)
bw.RunWorkerAsync(workQueue.Dequeue());
}
void CheckIfRunning(object sender, DoWorkEventArgs args)
{
BusRouteDataService server= BusRouteDataService.Current;
var route = (BusRouteIdModel)args.Argument;
if (route == null) return;
var vehicleFile = server.GetBusVehiclesFile(route);
var vehiclesOnRoute = RouteDataParser.ExtractBusVehicles(vehicleFile);
var helper = new RunningWorkerHelper { Route = route };
if (vehiclesOnRoute.Count > 0)
{
helper.Visible = Visibility.Visible;
}
else
{
helper.Visible = Visibility.Collapsed;
}
args.Result = helper;
}
void CheckRunningCompleted(object sender, RunWorkerCompletedEventArgs args)
{
var helper = (RunningWorkerHelper)args.Result;
if (helper != null)
helper.Route.IsRunning = helper.Visible;
StartWorkItem();
}
}
这是 BusRouteIdModel (供参考)
public class BusRouteIdModel : BusRouteId, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Visibility _isRunning;
/// <summary>
/// True when there is a bus active on this route
/// </summary>
public Visibility IsRunning
{
get { return _isRunning; }
set
{
if (value == _isRunning) return;
_isRunning = value;
OnPropertyChanged(new PropertyChangedEventArgs("IsRunnning"));
}
}
/// <summary>
/// True while path data for the route isn't available yet
/// </summary>
Visibility _isLoading;
public Visibility IsLoading
{
get { return _isLoading; }
set
{
if (value == _isLoading) return;
_isLoading = value;
OnPropertyChanged(new PropertyChangedEventArgs("IsLoading"));
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
if (PropertyChanged != null)
PropertyChanged(this, args);
}
}
public class BusRouteId
{
public String Uid { get; set; }
public String Name { get; set; }
}
这是绑定到页面上的列表框元素的数据(我正在使用 MVVM Light Toolkit):
public const string RouteIdsPropertyName = "RouteIds";
private ObservableCollection<BusRouteIdModel> _routeIds = null;
public ObservableCollection<BusRouteIdModel> RouteIds
{
get { return _routeIds; }
private set
{
if (_routeIds == value) return;
var oldValue = _routeIds;
_routeIds = value;
RaisePropertyChanged(RouteIdsPropertyName);
}
}
我像这样调用我的工作程序(参数.Uid id 是获取新数据的公交路线):
foreach (var route in RouteIds)
if (route.Uid == args.Uid)
runningWorker.QueueWorkItem(route);
2)奇怪的是,IsRunning 更改并未反映在 UI 中。我错过了什么?
3)我如何推广这个Queue + BackgroundWorker来处理其他任务? (我会使用任务池库,但 Silverlight 没有它。)我想要一个工作线程,这样 UI 线程就不会在地图页面上被饿死。
I've got an interesting issue with an app for Windows Phone 7.
Right now, I'm sending out some two dozen or so requests for small (a few KB) xml files to keep rapidly changing information (bus locations to be exact). I have a Timer ticking off every 10 sec to send out the requests asyncronously.
The data retreived is handled with an asynchronous callback to verify the request came back with a file, and stores the file into IsolatedStorage. When the data is needed (by the View-Model of the UI), the file is read from IsolatedStorage, parsed into internal objects (basically a GeoCoordinate and some strings) and used.
1) I'm running into the limitations of the phone's CPU here, just a bit. If I parse all the bus data to determine which bus routes are active on the UI thread, the thread noticably slows down. I moved the work into a bakground worker like this:
public class RunningWorkerHelper
{
public BusRouteIdModel Route { get; set; }
public Visibility Visible { get; set; }
}
public class RunningWorker
{
BackgroundWorker bw;
Queue<BusRouteIdModel> workQueue;
public RunningWorker()
{
bw = new BackgroundWorker();
workQueue = new Queue<BusRouteIdModel>();
bw.DoWork += CheckIfRunning;
bw.RunWorkerCompleted += CheckRunningCompleted;
}
public void QueueWorkItem(BusRouteIdModel route)
{
workQueue.Enqueue(route);
StartWorkItem();
}
void StartWorkItem()
{
if (!bw.IsBusy && workQueue.Count > 0)
bw.RunWorkerAsync(workQueue.Dequeue());
}
void CheckIfRunning(object sender, DoWorkEventArgs args)
{
BusRouteDataService server= BusRouteDataService.Current;
var route = (BusRouteIdModel)args.Argument;
if (route == null) return;
var vehicleFile = server.GetBusVehiclesFile(route);
var vehiclesOnRoute = RouteDataParser.ExtractBusVehicles(vehicleFile);
var helper = new RunningWorkerHelper { Route = route };
if (vehiclesOnRoute.Count > 0)
{
helper.Visible = Visibility.Visible;
}
else
{
helper.Visible = Visibility.Collapsed;
}
args.Result = helper;
}
void CheckRunningCompleted(object sender, RunWorkerCompletedEventArgs args)
{
var helper = (RunningWorkerHelper)args.Result;
if (helper != null)
helper.Route.IsRunning = helper.Visible;
StartWorkItem();
}
}
here's the BusRouteIdModel (for reference)
public class BusRouteIdModel : BusRouteId, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Visibility _isRunning;
/// <summary>
/// True when there is a bus active on this route
/// </summary>
public Visibility IsRunning
{
get { return _isRunning; }
set
{
if (value == _isRunning) return;
_isRunning = value;
OnPropertyChanged(new PropertyChangedEventArgs("IsRunnning"));
}
}
/// <summary>
/// True while path data for the route isn't available yet
/// </summary>
Visibility _isLoading;
public Visibility IsLoading
{
get { return _isLoading; }
set
{
if (value == _isLoading) return;
_isLoading = value;
OnPropertyChanged(new PropertyChangedEventArgs("IsLoading"));
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
if (PropertyChanged != null)
PropertyChanged(this, args);
}
}
public class BusRouteId
{
public String Uid { get; set; }
public String Name { get; set; }
}
This is data bound to a listbox element on the page (I'm using the MVVM Light Toolkit):
public const string RouteIdsPropertyName = "RouteIds";
private ObservableCollection<BusRouteIdModel> _routeIds = null;
public ObservableCollection<BusRouteIdModel> RouteIds
{
get { return _routeIds; }
private set
{
if (_routeIds == value) return;
var oldValue = _routeIds;
_routeIds = value;
RaisePropertyChanged(RouteIdsPropertyName);
}
}
And I call my worker like this (the args.Uid id's the bus route that got new data):
foreach (var route in RouteIds)
if (route.Uid == args.Uid)
runningWorker.QueueWorkItem(route);
2) Mysteriously, the IsRunning change isn't reflected in the UI. What did I miss?
3) How can I generalize this Queue + BackgroundWorker to handle other tasks? (I would use the Task Pool Library, but Silverlight does not have it.) I want to have a single worker so that the UI thread doesn't get starved on the map page.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
1)不是一个问题?
2) 由于拼写错误,UI 中的 IsRunning 未更新:
n 太多
3) 对于这样的线程,请尝试
ThreadPool
- 请参阅 http://wildermuth.com/2011/01/11/Architecting_WP7_-_Part_9_of_10_Threading1) Not a question?
2) IsRunning in the UI isn't updating because of a typo:
Too many n's
3) For threading like this, try
ThreadPool
- see http://wildermuth.com/2011/01/11/Architecting_WP7_-_Part_9_of_10_Threading