How to start a background process in Python?
Note: This answer is less current than it was when posted in 2009. Using the subprocess
module shown in other answers is now recommended in the docs
(Note that the subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using these functions.)
If you want your process to start in the background you can either use system()
and call it in the same way your shell script did, or you can spawn
it:
import os
os.spawnl(os.P_DETACH, 'some_long_running_command')
(or, alternatively, you may try the less portable os.P_NOWAIT
flag).
See the documentation here.
Android background process loading data from webpage every minute
Easy with WorkManager
, it's the most encouraged way for Scheduling Repeating background work in Android, see introduction.
As you say, the minimum repeating work request interval is restricted to 15 minutes, the only way to break it is to Repeatedly schedule the one-time work.
1. Setup Your Worker Class:
class ToastShower(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
withContext(Dispatchers.Main) { //ui related work must run in Main thread!!
Toast.makeText(applicationContext, "Hey, I'm Sam! This message will appear every 5 seconds.", Toast.LENGTH_SHORT).show()
}
return Result.success()
}
}
2. Setup Your Custom Application Class:
class WorkManagerApplication : Application() {
private val backgroundScope = CoroutineScope(Dispatchers.Default) //standard background thread
private val applicationContext = this
override fun onCreate() { //called when the app launches (same as Activity)
super.onCreate()
initWork()
}
private fun initWork() {
backgroundScope.launch { //all rnu in background thread
setupToastShowingWork(0) //no delay at first time
observeToastShowingWork() //observe work state changes, see below
}
}
private fun setupToastShowingWork(delayInSeconds: Long) { //must run in background thread
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED) //when using WiFi
.build()
val oneTimeRequest = OneTimeWorkRequestBuilder<ToastShower>() //【for breaking 15 minutes limit we have to use one time request】
.setInitialDelay(delayInSeconds, TimeUnit.SECONDS) //customizable delay (interval) time
.setConstraints(constraints)
.build()
WorkManager.getInstance(applicationContext).enqueueUniqueWork( //【must be unique!!】
ToastShower::class.java.simpleName, //work name, use class name for convenient
ExistingWorkPolicy.KEEP, //if new work comes in with same name, discard the new one
oneTimeRequest
)
}
private suspend fun observeToastShowingWork() {
withContext(Dispatchers.Main) { //must run in Main thread for using observeForever
WorkManager.getInstance(applicationContext).getWorkInfosForUniqueWorkLiveData(ToastShower::class.java.simpleName).observeForever {
if (it[0].state == WorkInfo.State.SUCCEEDED) { //when the work is done
backgroundScope.launch { //prevent from running in Main thread
setupToastShowingWork(5) //every 5 seconds
}
}
}
}
}
}
3. Setup AndroidManifest File:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.workmanagertest">
<application
android:name=".WorkManagerApplication" //【here, must!!!】
...
</application>
</manifest>
By setting up with above, the work (showing Toast
in my example) will be executed (or more clearly, schedule and execute) every 5 seconds no matter the app is in foreground or background or killed by system. Only way to stop it is either uninstall or go inside the app's setting to force-close it.
Demo: https://youtu.be/7IsQQppKqFs
PHP on a windows machine; Start process in background
Will this function from the PHP Manual help?
function runAsynchronously($path,$arguments) {
$WshShell = new COM("WScript.Shell");
$oShellLink = $WshShell->CreateShortcut("temp.lnk");
$oShellLink->TargetPath = $path;
$oShellLink->Arguments = $arguments;
$oShellLink->WorkingDirectory = dirname($path);
$oShellLink->WindowStyle = 1;
$oShellLink->Save();
$oExec = $WshShell->Run("temp.lnk", 7, false);
unset($WshShell,$oShellLink,$oExec);
unlink("temp.lnk");
}
How can I run code in a background thread and still access the UI?
While I'm glad you found a solution, I advise against using Application.DoEvents()
because it is bad practice.
Please see this blog post: Keeping your UI Responsive and the Dangers of Application.DoEvents.
Simply put, Application.DoEvents()
is a dirty workaround that makes your UI seem responsive because it forces the UI thread to handle all currently available window messages. WM_PAINT
is one of those messages which is why your window redraws.
However this has some backsides to it... For instance:
If you were to close the form during this "background" process it would most likely throw an error.
Another backside is that if the
ScanButtonInForm1()
method is called by the click of a button you'd be able to click that button again (unless you setEnabled = False
) and starting the process once more, which brings us to yet another backside:The more
Application.DoEvents()
-loops you start the more you occupy the UI thread, which will cause your CPU usage to rise rather quickly. Since every loop is run in the same thread your processor cannot schedule the work over different cores nor threads, so your code will always run on one core, eating as much CPU as possible.
The replacement is, of course, proper multithreading (or the Task Parallel Library, whichever you prefer). Regular multithreading actually isn't that hard to implement.
The basics
In order to create a new thread you only need to declare an instance of the Thread
class and pass a delegate to the method you want the thread to run:
Dim myThread As New Thread(AddressOf <your method here>)
...then you should set its IsBackground
property to True
if you want it to close automatically when the program closes (otherwise it keeps the program open until the thread finishes).
Then you just call Start()
and you have a running background thread!
Dim myThread As New Thread(AddressOf myThreadMethod)
myThread.IsBackground = True
myThread.Start()
Accessing the UI thread
The tricky part about multithreading is to marshal calls to the UI thread. A background thread generally cannot access elements (controls) on the UI thread because that might cause concurrency issues (two threads accessing the same control at the same time). Therefore you must marshal your calls to the UI by scheduling them for execution on the UI thread itself. That way you will no longer have the risk of concurrency because all UI related code is run on the UI thread.
To marhsal calls to the UI thread you use either of the Control.Invoke()
or Control.BeginInvoke()
methods. BeginInvoke()
is the asynchronous version, which means it doesn't wait for the UI call to complete before it lets the background thread continue with its work.
One should also make sure to check the Control.InvokeRequired
property, which tells you if you already are on the UI thread (in which case invoking is extremely unnecessary) or not.
The basic InvokeRequired/Invoke
pattern looks like this (mostly for reference, keep reading below for shorter ways):
'This delegate will be used to tell Control.Invoke() which method we want to invoke on the UI thread.
Private Delegate Sub UpdateTextBoxDelegate(ByVal TargetTextBox As TextBox, ByVal Text As String)
Private Sub myThreadMethod() 'The method that our thread runs.
'Do some background stuff...
If Me.InvokeRequired = True Then '"Me" being the current form.
Me.Invoke(New UpdateTextBoxDelegate(AddressOf UpdateTextBox), TextBox1, "Status update!") 'We are in a background thread, therefore we must invoke.
Else
UpdateTextBox(TextBox1, "Status update!") 'We are on the UI thread, no invoking required.
End If
'Do some more background stuff...
End Sub
'This is the method that Control.Invoke() will execute.
Private Sub UpdateTextBox(ByVal TargetTextBox As TextBox, ByVal Text As String)
TargetTextBox.Text = Text
End Sub
New UpdateTextBoxDelegate(AddressOf UpdateTextBox)
creates a new instance of the UpdateTextBoxDelegate
that points to our UpdateTextBox
method (the method to invoke on the UI).
However as of Visual Basic 2010 (10.0) and above you can use Lambda expressions which makes invoking much easier:
Private Sub myThreadMethod()
'Do some background stuff...
If Me.InvokeRequired = True Then '"Me" being the current form.
Me.Invoke(Sub() TextBox1.Text = "Status update!") 'We are in a background thread, therefore we must invoke.
Else
TextBox1.Text = "Status update!" 'We are on the UI thread, no invoking required.
End If
'Do some more background stuff...
End Sub
Now all you have to do is type Sub()
and then continue typing code like if you were in a regular method:
If Me.InvokeRequired = True Then
Me.Invoke(Sub()
TextBox1.Text = "Status update!"
Me.Text = "Hello world!"
Label1.Location = New Point(128, 32)
ProgressBar1.Value += 1
End Sub)
Else
TextBox1.Text = "Status update!"
Me.Text = "Hello world!"
Label1.Location = New Point(128, 32)
ProgressBar1.Value += 1
End If
And that's how you marshal calls to the UI thread!
Making it simpler
To make it even more simple to invoke to the UI you can create an Extension method that does the invoking and InvokeRequired
check for you.
Place this in a separate code file:
Imports System.Runtime.CompilerServices
Public Module Extensions
''' <summary>
''' Invokes the specified method on the calling control's thread (if necessary, otherwise on the current thread).
''' </summary>
''' <param name="Control">The control which's thread to invoke the method at.</param>
''' <param name="Method">The method to invoke.</param>
''' <param name="Parameters">The parameters to pass to the method (optional).</param>
''' <remarks></remarks>
<Extension()> _
Public Function InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object()) As Object
If Parameters IsNot Nothing AndAlso _
Parameters.Length = 0 Then Parameters = Nothing
If Control.InvokeRequired = True Then
Return Control.Invoke(Method, Parameters)
Else
Return Method.DynamicInvoke(Parameters)
End If
End Function
End Module
Now you only need to call this single method when you want to access the UI, no additional If-Then-Else
required:
Private Sub myThreadMethod()
'Do some background stuff...
Me.InvokeIfRequired(Sub()
TextBox1.Text = "Status update!"
Me.Text = "Hello world!"
Label1.Location = New Point(128, 32)
End Sub)
'Do some more background stuff...
End Sub
Returning objects/data from the UI with InvokeIfRequired()
With my InvokeIfRequired()
extension method you can also return objects or data from the UI thread in a simple manner. For instance if you want the width of a label:
Dim LabelWidth As Integer = Me.InvokeIfRequired(Function() Label1.Width)
Example
The following code will increment a counter that tells you for how long the thread has run:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim CounterThread As New Thread(AddressOf CounterThreadMethod)
CounterThread.IsBackground = True
CounterThread.Start()
Button1.Enabled = False 'Make the button unclickable (so that we cannot start yet another thread).
End Sub
Private Sub CounterThreadMethod()
Dim Time As Integer = 0
While True
Thread.Sleep(1000) 'Wait for approximately 1000 ms (1 second).
Time += 1
Me.InvokeIfRequired(Sub() Label1.Text = "Thread has been running for: " & Time & " seconds.")
End While
End Sub
Hope this helps!
Related Topics
Rake: Logging Any Task Executing
Fresh Install of Rvm in Ubuntu Isn't Letting Me Install Gems (Zlib Error)
Get Available Diskspace in Ruby
Alter Rails Params Hash from Rack Middleware
Terminal Not Executing Ruby Files
Have a Parent Class's Method Access the Subclass's Constants
"No Available Formula for Gcc46" While Installing Ruby 1.9.3 on Os X with Rvm:
Compute Geo Distance in Elasticsearch
Implicit Argument Passing of Super from Method Defined by Define_Method() Is Not Supported
How to Remove All Characters in a String Until a Substring Is Matched, in Ruby
What Are Factory_Girl Transient Attributes? Why Would I Use One
Gmail Threading, Imap and Ruby
Converting Time in Utc to Pacific Time
Argument Out of Range Rails 4 and Bootstrap3-Datetimepicker-Rails
Devise Not Working Well with Multiple Subdomains on Ror3 Application