That is not what single threaded means. That is putting a shell command in the background. I can’t recall Apple saying that a do shell script is single threaded but they meant the event do shell script, not the shell.
You can check this yourself easily. In script editor open 2 windows, in window 1 open do a shell command “sleep” for a long time, in window 2 do a simple short command like “ls”. Now start script in window 1 and before the script is finished in window 1 start the script in window 2. Even if script editor is multi threaded, you cannot run two do shell scripts simultaneous.
I will keep Apple Events out of it, I know that Applescript is single threaded within the same instance of it, and that there is one instance per current application, and I thought i did read that section in the Tech Note TN2065, but there they state what I wrote above, about starting background processes.
I have to refind where I read it, but it wasn’t in the Technote.
Yes, but you can have several instances of it? You can have some folder action running, you can have an agent running in the background, while you execute a script in Script Editor, and all things happens at the same time, with regards to the applescript code, since they run in their own instance?
Or, is it more that they have their own context, in their current app, and that those events are then treated by a global AppleScript instance?
You can have more instances of an NSAppleScript object. But you can’t have more instances of AppleScript itself, a virtual machine interpreting byte code. They are not the same.
An NSAppleScript object is a script – I think you mean AppleScript component instances. But the point about AppleScript itself is the important one in terms of threading.
So, I am right if I state that AppleScript is single threaded in its instance of the AppleScript Component. Events are multiplexed by the EventManager, but when events queue up at one other AppleScript Component, or App for that matter, then the events are queued, so everything is really single threaded in the end.
Threading is pretty much meaningless in terms of AppleScript. Event sending can be done on multiple threads, and stuff is handled asynchronously, so there’s no thread stalling.
At least some processes like System Events, would process one event at a time, at least in the past, and I believe it is so, now too. that was what I meant, by queuing up. the Eventmanager, works like a broker, and will effectively pass one event from a client, to a server, which can be viewed as multiplexing, since it leaves the single component object that sent the event with the impression, that it is the only one that deals with System Events for instance, and that view holds for practical reasons, since System Events processes one event at a time as they have arrived, (as I have understood it), and then they are passed back to the broker (Eventmanager), that sends them back to the correct receipient.
Aside: I read a paper on the Plan 9 Os just recently. I have always believed that the one of the two main objectives of an Operating System is to provide a Machine Model. The guys behind Plan 9 has strucken it further, I believe I read that their view is to provide multiplexed hardware to processes. -I have to reskim the paper, it is only so much time.
This might make it more obvious. Run the following in the foreground, and look at Console. You’ll see that when the script on the background thread – which is also running on a separate instance – is run, the first script is put on hold until it’s finished.
use framework "Foundation"
use framework "OSAKit"
on doStuff()
-- create a new AppleScript instance
set anOSALanguageInstance to current application's OSALanguageInstance's languageInstanceWithLanguage:(current application's OSALanguage's defaultLanguage())
-- make script and run it from the new instance
set theSource to "use framework \"Foundation\"
repeat with i from 1 to 20
delay 0.1
current application's NSLog(\"On second instance, second thread %d\", i) -- writes to Console
end repeat"
set theScript to current application's OSAScript's alloc()'s initWithSource:theSource fromURL:(missing value) languageInstance:anOSALanguageInstance usingStorageOptions:(current application's OSANull)
set {theResult, theError} to theScript's compileAndReturnError:(reference)
theScript's executeAndReturnError:(reference)
end doStuff
on doItInTheBackground()
-- call the above handler on a separate background thread
my performSelectorInBackground:"doStuff" withObject:(missing value)
end doItInTheBackground
-- set the above to run after 1 second
my performSelector:"doItInTheBackground" withObject:(missing value) afterDelay:1
-- start a repeat loop
repeat with i from 1 to 20
delay 0.1
current application's NSLog("On default instance, first thread %d", i) -- writes to Console
end repeat
Just to be clear about something, Shane’s example, works the way it works, because both threads belong to the same application context, so they share the scripting component, which is a pretty much unique “AppleScript Enviroment” for that application, so that every application indeed has their unique “AppleScript Environment” that can execute in parallell, to the extent that the applications them selves executes in parallell, limited only by the fact that several running application’s Applescripts, may address the same application with AppleEvents, in that case, things must be processed in a kind of sequence, since AppleScript is single threaded.
No, they don’t. The main script is run on the default scripting component all app’s have, but the other runs on its own component. But they are, of course, part of the same application – current application, from which AppleScript inherits, is the same in both cases.
I agree, I know nothing about how that scripting component for the second thread is created, but the scripting component for the main thread must be halted, since they both belong to the same application context, (not process context), because an application context, can have just one scripting component.
I think I know what you are getting at, but the term “scripting component” has a specific meaning, and in that context, applications can have as many as they want. Every document in Script Editor, for example, has its own scripting component these days – that’s why changing things like text item delimiters in one script doesn’t affect them in another.
I have adopted Matt Neuburg’s view of things, which can be outdated for all I know by know, he talks about a component Manager, that forks out copies of the Script component to apps. I found the description of what is going on on page 48, second paragraph, in “Applescript the Definitive guide”, the figure he uses for referral, is figure 3-2.
And your statement about text item delimiters, holds, as long as you don’t specify AppleScript’s text item delimiters I think. Because then I think you alter them in the “mother ship” so to speak. The same goes with formatting preferences, in an editor, they also alter the “mother ship”.
I have a thought model of it all, that the Scripting Component of an app, is kind of like process 0 in the unix env, where every other process is made out of a copy of this eventually, it may inherit the differences that other processes above it in the hierarchy has done to the image eventually.
So, when an app has several scripting components, they are all inherited kind of from the apps “main” scripting component, and if one of them runs, then the other has to be halted, since the Scripting component of an app, can just have one pair of “telephone lines” connected with the event manager at a time.
That’s correct, but what Matt doesn’t mention, presumably to keep things simple, is that an application can have more than one such copy. Most apps don’t bother, but it makes sense for editors – and you also get an extra one if you run the script I posted above.
In fact, Script Editor creates a new component instance one every time you compile a script. That’s how, these days, you can change the capitalization of a variable; if a single component was used, as in the old days, you’d be stuck with the initial capitalization until you quit and relaunched.
Two minutes in Script Editor will demonstrate otherwise. They are a property of an instance of AppleScript, just like pi, return, or even result.
Here’s a simple test, two scripts:
set AppleScript's text item delimiters to {"blah"}
display dialog {"a", "b", "c"} as text
And:
display dialog {"a", "b", "c"} as text
Run them in order in Script Editor, then save them and run them in order from the menu or panel of an application that has its own scripts menu or panel.
Formatting preferences are only used by the decompiler, as as DJ suggested earlier, there’s only one of those. Nonetheless, changes are done via scripting components.
I realized there was a second copy around, but also that only one script component can be active for an app at a time.
I think I conceptually went global before you did on this subject, there is no disagreeement really about this, at least now it isn’t.
Thank you for your enlightment, Text Item delimiters got a whole less scarier now, I guess this has been around since Snow Leopard? -I really wouldn’t try that on Os X Tiger!
And I also now understand the text formatting better, because it can be confusing at times, when the text formatting changes, back, and kind of overrides my last preferences, when I had set preferences in earlier versions, they kind of “stuck”.
I haven’t fully investigated, how things get confusing, when the script editor preferences suddenly changes, by me loading a script, but now I know where to look at least.
I use the gnu utilities too, which sometimes confuses stuff, because of the slightly different command line options.
So, I thought I’d share this snippet, that lets you pick the correct manual page, as I somehow have gotten tired of typing those lines over and over in the terminal.
I should have named it aww, but I settled for whman.